// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. 

using System;
using System.Collections;
#if FxCop
using System.Collections.Generic;
using AssemblyReferenceList = Microsoft.Cci.AssemblyReferenceCollection;
using AttributeList = Microsoft.Cci.AttributeNodeCollection;
using BlockList = Microsoft.Cci.BlockCollection;
using ExpressionList = Microsoft.Cci.ExpressionCollection;
using InstructionList = Microsoft.Cci.InstructionCollection;
using Int32List = System.Collections.Generic.List<int>;
using InterfaceList = Microsoft.Cci.InterfaceCollection;
using LocalList = Microsoft.Cci.LocalCollection;
using MemberList = Microsoft.Cci.MemberCollection;
using MethodList = Microsoft.Cci.MethodCollection;
using ModuleReferenceList = Microsoft.Cci.ModuleReferenceCollection;
using NamespaceList = Microsoft.Cci.NamespaceCollection;
using ParameterList = Microsoft.Cci.ParameterCollection;
using ResourceList = Microsoft.Cci.ResourceCollection;
using SecurityAttributeList = Microsoft.Cci.SecurityAttributeCollection;
using StatementList = Microsoft.Cci.StatementCollection;
using TypeNodeList = Microsoft.Cci.TypeNodeCollection;
using Win32ResourceList = Microsoft.Cci.Win32ResourceCollection;
using Property = Microsoft.Cci.PropertyNode;
using Module = Microsoft.Cci.ModuleNode;
using Class = Microsoft.Cci.ClassNode;
using Interface = Microsoft.Cci.InterfaceNode;
using Event = Microsoft.Cci.EventNode;
using Return = Microsoft.Cci.ReturnNode;
using Throw = Microsoft.Cci.ThrowNode;
#endif
#if CCINamespace
using Microsoft.Cci;
#else
using System.Compiler;
#endif
using System.Diagnostics;
using System.Globalization;
using Marshal = System.Runtime.InteropServices.Marshal;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;

#if CCINamespace
namespace Microsoft.Cci.Metadata{
#else
namespace System.Compiler.Metadata{
#endif

#if !ROTOR
  enum CorOpenFlags : uint{
    ofRead      =   0x00000000,     // Open scope for read
    ofWrite     =   0x00000001,     // Open scope for write.
    ofCopyMemory =  0x00000002,     // Open scope with memory. Ask metadata to maintain its own copy of memory.
    ofCacheImage =  0x00000004,     // EE maps but does not do relocations or verify image
    ofNoTypeLib =   0x00000080,     // Don't OpenScope on a typelib.
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("809c652e-7396-11d2-9771-00A0C9B4D50C")]
  interface IMetaDataDispenser{
    void DefineScope (ref Guid clsid, uint createFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object retval);    
    [PreserveSig]
    int OpenScope (string scope, uint openFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object import);
    void OpenScopeOnMemory (IntPtr data, uint dataSize, uint openFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object retval);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("AA544D42-28CB-11d3-BD22-0000F80849BD")]
  interface ISymUnmanagedBinder{
    [PreserveSig]
    int GetReaderForFile([MarshalAs(UnmanagedType.IUnknown)] object importer, string filename, string searchPath, out ISymUnmanagedReader reader);
    ISymUnmanagedReader GetReaderForStream([MarshalAs(UnmanagedType.IUnknown)] object importer, [MarshalAs(UnmanagedType.IUnknown)] object stream);
  }
  [ComImport, Guid("ACCEE350-89AF-4ccb-8B40-1C2C4C6F9434"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(false)]
  interface ISymUnmanagedBinder2: ISymUnmanagedBinder{
    void GetReaderForFile(IntPtr importer, [MarshalAs(UnmanagedType.LPWStr)] String filename, [MarshalAs(UnmanagedType.LPWStr)] String SearchPath, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader retVal);
    void GetReaderFromStream(IntPtr importer, IntPtr stream, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader retVal);
    [PreserveSig]
    int GetReaderForFile2([MarshalAs(UnmanagedType.IUnknown)] object importer, [MarshalAs(UnmanagedType.LPWStr)] String fileName, [MarshalAs(UnmanagedType.LPWStr)] String searchPath, int searchPolicy, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader pRetVal);
//    void GetReaderForFile3(IntPtr importer, [MarshalAs(UnmanagedType.LPWStr)] String fileName, [MarshalAs(UnmanagedType.LPWStr)] String searchPath, int searchPolicy, IntPtr callback, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader pRetVal);
  }
  [ComImport, Guid("AA544D41-28CB-11d3-BD22-0000F80849BD")]
  class CorSymBinder{ 
  }
  [ComImport, Guid("0A29FF9E-7F9C-4437-8B11-F424491E3931")]
  class CorSymBinder2{
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B4CE6286-2A6B-3712-A3B7-1EE1DAD467B5")]
  interface ISymUnmanagedReader{
    ISymUnmanagedDocument GetDocument(string url, ref Guid language, ref Guid languageVendor, ref Guid documentType);
    void GetDocuments(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ISymUnmanagedDocument[] docs);
    uint GetUserEntryPoint();
    [PreserveSig]
    int GetMethod(uint token, ref ISymUnmanagedMethod method);
    ISymUnmanagedMethod GetMethodByVersion(uint token, int version);
    void GetVariables(uint parent, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ISymUnmanagedVariable[] vars);
    void GetGlobalVariables(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ISymUnmanagedVariable[] vars);
    ISymUnmanagedMethod GetMethodFromDocumentPosition(ISymUnmanagedDocument document, uint line, uint column);
    void GetSymAttribute(uint parent, string name, ulong size, ref uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] byte[] buffer);
    void GetNamespaces(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] namespaces);
    void Initialize([MarshalAs(UnmanagedType.IUnknown)] object importer, string filename, string searchPath, [MarshalAs(UnmanagedType.IUnknown)] object stream);
    void UpdateSymbolStore(string filename, [MarshalAs(UnmanagedType.IUnknown)] object stream);
    void ReplaceSymbolStore(string filename, [MarshalAs(UnmanagedType.IUnknown)] object stream);
    void GetSymbolStoreFileName(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] char[] name);
    void GetMethodsFromDocumentPosition(ISymUnmanagedDocument document, uint line, uint column, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)] ISymUnmanagedMethod[] retval);
    void GetDocumentVersion(ISymUnmanagedDocument doc, out int version, out bool isLatest);
    void GetMethodVersion(ISymUnmanagedMethod method, out int version);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B62B923C-B500-3158-A543-24F307A8B7E1")]
  interface ISymUnmanagedMethod{
    uint GetToken();
    uint GetSequencePointCount();
    ISymUnmanagedScope GetRootScope();
    ISymUnmanagedScope GetScopeFromOffset(uint offset);
    uint Getoffset(ISymUnmanagedDocument document, uint line, uint column);
    void GetRanges(ISymUnmanagedDocument document, uint line, uint column, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)] uint[] ranges);
    void GetParameters(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ISymUnmanagedVariable[] parms);
    IntPtr GetNamespace();
    bool GetSourceStartEnd([MarshalAs(UnmanagedType.LPArray,SizeConst=2)] ISymUnmanagedDocument[] docs, [MarshalAs(UnmanagedType.LPArray)] uint[] lines, [MarshalAs(UnmanagedType.LPArray)] uint[] columns);
    void GetSequencePoints(uint size, out uint length, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] offsets,
      [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.IUnknown, SizeParamIndex=0)] IntPtr[] documents,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] lines,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] columns,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] endLines,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] endColumns);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("40DE4037-7C81-3E1E-B022-AE1ABFF2CA08")]
  interface ISymUnmanagedDocument{
    void GetURL(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] char[] url);
    void GetDocumentType(out Guid retval);
    void GetLanguage(out Guid retval);
    void GetLanguageVendor(out Guid retval);
    void GetCheckSumAlgorithmId(out Guid retval);
    void GetCheckSum(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] data);
    uint FindClosestLine(uint line);
    bool HasEmbeddedSource();
    uint GetSourceLength();
    void GetSourceRange(uint startLine, uint startColumn, uint endLine, uint endColumn, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=4)] byte[] source);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("9F60EEBE-2D9A-3F7C-BF58-80BC991C60BB")]
  interface ISymUnmanagedVariable{
    void GetName(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] char[] name);
    uint GetAttributes();
    void GetSignature(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] name);
    uint GetAddressKind();
    uint GetAddressField1();
    uint GetAddressField2();
    uint GetAddressField3();
    uint GetStartOffset();
    uint GetEndOffset();
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("68005D0F-B8E0-3B01-84D5-A11A94154942")]
  interface ISymUnmanagedScope{
    ISymUnmanagedMethod GetMethod();
    ISymUnmanagedScope GetParent();
    void GetChildren (uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] children);
    uint GetStartOffset();
    uint GetEndOffset();
    uint GetLocalCount();
    void GetLocals(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] locals);
    void GetNamespaces(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] namespaces);
  }
#endif
  internal sealed class UnmanagedBuffer : IDisposable{
    internal IntPtr Pointer;
    internal UnmanagedBuffer(int length){
      this.Pointer = Marshal.AllocHGlobal(length);
    }
    public void Dispose(){
      if (this.Pointer != IntPtr.Zero)
        Marshal.FreeHGlobal(this.Pointer);
      this.Pointer = IntPtr.Zero;
      GC.SuppressFinalize(this);
    }
    ~UnmanagedBuffer(){
      this.Dispose();
    }
  } 
  internal unsafe class Reader : IDisposable{
    private string directory;
    private string fileName;
    private bool doNotLockFile;
    private Module/*!*/ module = new Module();
    internal TypeNode currentType;
    private long sortedTablesMask;
    internal MetadataReader/*!*/ tables;
    private UnmanagedBuffer unmanagedBuffer;
    private int bufferLength;
    private IDictionary/*!*/ localAssemblyCache; //use for simple names
    internal readonly static IDictionary/*!*/ StaticAssemblyCache = new SynchronizedWeakDictionary(); //use for strong names
    private bool useStaticCache;
    //^ [Microsoft.Contracts.SpecInternal]
    private TrivialHashtable namespaceTable;
    internal NamespaceList namespaceList;
#if CodeContracts
    internal PdbInfo pdbInfo;
#endif
#if !ROTOR
    internal ISymUnmanagedReader debugReader;
    private System.Collections.Generic.Dictionary<IntPtr,UnmanagedDocument> debugDocuments;
#endif
#if FxCop
    internal static bool probeGAC = true;
#endif
    internal bool getDebugSymbols;
    private bool getDebugSymbolsFailed;
    private TypeNodeList currentTypeParameters;
    private TypeNodeList currentMethodTypeParameters;
    internal bool preserveShortBranches;
#if !MinimalReader
    internal unsafe Reader(byte[]/*!*/ buffer, IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches) {
      Debug.Assert(buffer != null);
      if (localAssemblyCache == null) localAssemblyCache = new Hashtable();
      this.localAssemblyCache = localAssemblyCache;
      this.getDebugSymbols = getDebugInfo;
      this.doNotLockFile = false;
      this.useStaticCache = useStaticCache;
      this.preserveShortBranches = preserveShortBranches;
      int n = this.bufferLength = buffer.Length;
      this.unmanagedBuffer = new UnmanagedBuffer(n);
      //^ base();
      byte* pb = (byte*)this.unmanagedBuffer.Pointer;
      for (int i = 0; i < n; i++) *pb++ = buffer[i];
    }
#endif
    internal Reader(string/*!*/ fileName, IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches){
      if (localAssemblyCache == null) localAssemblyCache = new Hashtable();
      this.localAssemblyCache = localAssemblyCache;
      fileName = System.IO.Path.GetFullPath(fileName);
      this.fileName = fileName;
      this.directory = System.IO.Path.GetDirectoryName(fileName);
      this.getDebugSymbols = getDebugInfo;
      this.doNotLockFile = doNotLockFile;
      this.useStaticCache = useStaticCache;
      this.preserveShortBranches = preserveShortBranches;
      //^ base();
    }
    internal Reader(IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches){
      if (localAssemblyCache == null) localAssemblyCache = new Hashtable();
      this.localAssemblyCache = localAssemblyCache;
      this.directory = System.IO.Directory.GetCurrentDirectory();
      this.getDebugSymbols = getDebugInfo;
      this.doNotLockFile = doNotLockFile;
      this.useStaticCache = useStaticCache;
      this.preserveShortBranches = preserveShortBranches;
      //^ base();
    }
    public void Dispose(){
      if (this.unmanagedBuffer != null)
        this.unmanagedBuffer.Dispose();
      this.unmanagedBuffer = null;
      if (this.tables != null)
        this.tables.Dispose();
      //this.tables = null;
#if !ROTOR
      if (this.debugReader != null)
        Marshal.ReleaseComObject(this.debugReader);
      this.debugReader = null;
      this.debugDocuments = null;
#endif
    }
    private unsafe void SetupReader(){
      Debug.Assert(this.localAssemblyCache != null);
#if !ROTOR
      if (this.doNotLockFile){
#endif
        using (System.IO.FileStream inputStream = new System.IO.FileStream(this.fileName, 
                 System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)){
          this.ReadFileIntoUnmanagedBuffer(inputStream);
        }
#if !ROTOR
      }
      if (this.unmanagedBuffer == null)
        this.tables = new MetadataReader(this.fileName); //Uses a memory map that locks the file
      else
#endif
        this.tables = new MetadataReader((byte*)this.unmanagedBuffer.Pointer, this.bufferLength);
      //^ assume this.tables.tablesHeader != null;
      this.sortedTablesMask = this.tables.tablesHeader.maskSorted;
    }
#if !ROTOR
    [DllImport("kernel32", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern unsafe bool ReadFile(IntPtr FileHandle, byte* Buffer, int NumberOfBytesToRead, int* NumberOfBytesRead, IntPtr Overlapped);
#endif
    private unsafe void ReadFileIntoUnmanagedBuffer(System.IO.FileStream/*!*/ inputStream) {
      long size = inputStream.Seek(0, System.IO.SeekOrigin.End);
      if (size > int.MaxValue) throw new System.IO.FileLoadException();
      inputStream.Seek(0, System.IO.SeekOrigin.Begin);
      int n = (int)size;
      this.bufferLength = n;
      this.unmanagedBuffer = new UnmanagedBuffer(n);
      byte* pb = (byte*)this.unmanagedBuffer.Pointer;
#if !ROTOR
#if WHIDBEY && !OldWhidbey
      if (!Reader.ReadFile(inputStream.SafeFileHandle.DangerousGetHandle(), pb, n, &n, IntPtr.Zero)) throw new System.IO.FileLoadException();
#else
      if (!Reader.ReadFile(inputStream.Handle, pb, n, &n, IntPtr.Zero)) throw new System.IO.FileLoadException();
#endif
#else
      //Read a fixed length block at a time, so that the GC does not come under pressure from lots of large byte arrays.
      int bufferLen = 8096;
      byte[] buffer = new byte[bufferLen];
      while (n > 0){
        if (n < bufferLen) bufferLen = n;
        inputStream.Read(buffer, 0, bufferLen);
        for (int i = 0; i < bufferLen; i++) *pb++ = buffer[i];
        n -= bufferLen;
      }
#endif
    }
    internal void SetupDebugReader(string filename, string pdbSearchPath){
#if CodeContracts
      string pdbFileName = BetterPath.ChangeExtension(filename, "pdb");
      this.getDebugSymbolsFailed = true;
      //TODO: use search path
      if (System.IO.File.Exists(pdbFileName))
      {
        using (System.IO.FileStream inputStream = new System.IO.FileStream(pdbFileName,
                 System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
        {
          this.pdbInfo = new PdbInfo(inputStream, this);
          this.getDebugSymbolsFailed = false;
        }
      }
#endif
#if !ROTOR
      if (filename == null) return;
      CorSymBinder binderObj1 = null;
      CorSymBinder2 binderObj2 = null;
      getDebugSymbolsFailed = false;
      object importer = null;
      try{
        int hresult = 0;
        try{
          binderObj2 = new CorSymBinder2();
          ISymUnmanagedBinder2 binder2 = (ISymUnmanagedBinder2)binderObj2;
#if !NoWriter          
            importer = new Ir2md(new Module());
#else
            importer = new EmptyImporter();
#endif
          hresult = binder2.GetReaderForFile(importer, filename, pdbSearchPath, out this.debugReader);
        }
        catch (COMException e){
          // could not instantiate ISymUnmanagedBinder2, fall back to ISymUnmanagedBinder
          if ((uint)e.ErrorCode == 0x80040111){
            binderObj1 = new CorSymBinder();
            ISymUnmanagedBinder binder = (ISymUnmanagedBinder)binderObj1;
            hresult = binder.GetReaderForFile(importer, filename, null, out this.debugReader);
          }else{
            throw;
          }
        }
        switch ((uint)hresult){
          case 0x0: break; 
          case 0x806d0005:  // EC_NOT_FOUND
          case 0x806d0014 : // EC_INVALID_EXE_TIMESTAMP
#if FxCop
            this.getDebugSymbols = false;
            this.getDebugSymbolsFailed = true;
#else
            // Sometimes GetReaderForFile erroneously reports missing pdb files as being "out of date", 
            // so we check if the file actually exists before reporting the error.
            // The mere absence of a pdb file is not an error. If not present, do not report.
            if (System.IO.File.Exists(System.IO.Path.ChangeExtension(filename, ".pdb")))
              throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.PdbAssociatedWithFileIsOutOfDate, filename));
#endif            
            break;
          default:
            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 
              ExceptionStrings.GetReaderForFileReturnedUnexpectedHResult, hresult.ToString("X")));
        }
#if !FxCop
      }catch (Exception e){
        this.getDebugSymbols = false;
        this.getDebugSymbolsFailed = true;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
#endif
      }finally{
        if (binderObj1 != null) Marshal.ReleaseComObject(binderObj1);
        if (binderObj2 != null) Marshal.ReleaseComObject(binderObj2);
      }
#endif // !ROTOR
    }
#if !MinimalReader
    private AssemblyNode ReadAssembly()
    {
      return ReadAssembly(null);
    }
    private AssemblyNode ReadAssembly(AssemblyNode.PostAssemblyLoadProcessor postLoadEvent){
#else
    private AssemblyNode ReadAssembly(){
#endif
      try{
        AssemblyNode assembly = new AssemblyNode(new Module.TypeNodeProvider(this.GetTypeFromName), 
          new Module.TypeNodeListProvider(this.GetTypeList), new Module.CustomAttributeProvider(this.GetCustomAttributesFor),
          new Module.ResourceProvider(this.GetResources), this.directory);
        assembly.reader = this;
        this.ReadModuleProperties(assembly);
        this.ReadAssemblyProperties(assembly); //Hashvalue, Name, etc.
        this.module = assembly;
        this.ReadAssemblyReferences(assembly);
        this.ReadModuleReferences(assembly);
        AssemblyNode cachedAssembly = this.GetCachedAssembly(assembly);
        if (cachedAssembly != null) return cachedAssembly;
        if (this.getDebugSymbols) assembly.SetupDebugReader(null);
#if !MinimalReader
        if (postLoadEvent != null) {
          assembly.AfterAssemblyLoad += postLoadEvent;
          postLoadEvent(assembly);
        }
#endif
        return assembly;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return null;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return this.module as AssemblyNode;
      }
#else
      }finally{}
#endif
    }
    private AssemblyNode GetCachedAssembly(AssemblyNode/*!*/ assembly) {
      //Always return the one true mscorlib. Things get too weird if more than one mscorlib is being read at the same time.
      //if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assembly.Name && CoreSystemTypes.SystemAssembly.reader != null) {
      //  if (CoreSystemTypes.SystemAssembly.reader != this) {
      //    if (this.getDebugSymbols && !CoreSystemTypes.SystemAssembly.reader.getDebugSymbols && !CoreSystemTypes.SystemAssembly.reader.getDebugSymbolsFailed)
      //      CoreSystemTypes.SystemAssembly.SetupDebugReader(null);
      //    this.Dispose();
      //  }
      //  return CoreSystemTypes.SystemAssembly;
      //}
      if (assembly.PublicKeyOrToken == null || assembly.PublicKeyOrToken.Length == 0){
        AssemblyNode cachedAssembly = null;
        if (assembly.Location != null)
          cachedAssembly = this.localAssemblyCache[assembly.Location] as AssemblyNode;
        if (cachedAssembly == null && assembly.Name != null){
          cachedAssembly = this.localAssemblyCache[assembly.Name] as AssemblyNode;
          if (cachedAssembly != null && assembly.Location != null)
            this.localAssemblyCache[assembly.Location] = cachedAssembly;
        }
        if (cachedAssembly != null) {
          if (cachedAssembly.reader != this && cachedAssembly.reader != null){
            if (this.getDebugSymbols && !cachedAssembly.reader.getDebugSymbols && !cachedAssembly.reader.getDebugSymbolsFailed)
              cachedAssembly.SetupDebugReader(null);
            this.Dispose();
          }
          return cachedAssembly;
        }
        lock (Reader.StaticAssemblyCache) {
          if (assembly.Name != null)
            this.localAssemblyCache[assembly.Name] = assembly;
          if (this.fileName != null)
            this.localAssemblyCache[this.fileName] = assembly;
        }
      }else{
        string assemblyStrongName = assembly.StrongName;
        AssemblyNode cachedAssembly = null;
        if (this.useStaticCache){
          //See if assembly is a platform assembly (and apply unification)
          AssemblyReference assemblyReference = new AssemblyReference(assembly);
          AssemblyReference aRef = (AssemblyReference)TargetPlatform.AssemblyReferenceFor[Identifier.For(assemblyReference.Name).UniqueIdKey];
          if (aRef != null && assemblyReference.Version != null && aRef.Version >= assemblyReference.Version && aRef.MatchesIgnoringVersion(assemblyReference)) {
            AssemblyNode platformAssembly = aRef.assembly;
            if (platformAssembly == null) {
              Debug.Assert(aRef.Location != null);
              if (Path.GetFullPath(aRef.Location) == assembly.Location) {
                if (aRef.Version != assemblyReference.Version) {
                  HandleError(assembly, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.BadTargetPlatformLocation, assembly.Name, TargetPlatform.PlatformAssembliesLocation, assembly.Version, aRef.Version));
                }
                lock (Reader.StaticAssemblyCache) {
                  Reader.StaticAssemblyCache[assemblyStrongName] = assembly;
                  if (aRef.Location != null)
                    Reader.StaticAssemblyCache[aRef.Location] = assembly;
                  aRef.Assembly = assembly;
                }
                return null; //Prevents infinite recursion
              }
              platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
            }
            if (platformAssembly != null) {
              lock (Reader.StaticAssemblyCache) {
                if (aRef.Location != null)
                  Reader.StaticAssemblyCache[aRef.Location] = platformAssembly;
                Reader.StaticAssemblyCache[assemblyStrongName] = platformAssembly;
              }
              return aRef.assembly = platformAssembly;
            }
          }
          cachedAssembly = Reader.StaticAssemblyCache[assemblyStrongName] as AssemblyNode;
          if (cachedAssembly != null){
            if (aRef == null && assembly.FileLastWriteTimeUtc > cachedAssembly.FileLastWriteTimeUtc &&
              assembly.Location != null && cachedAssembly.Location != null && assembly.Location == cachedAssembly.Location) {
              lock (Reader.StaticAssemblyCache) {
                Reader.StaticAssemblyCache[assemblyStrongName] = assembly;
              }
              return null;
            }
            if (cachedAssembly.reader != this && cachedAssembly.reader != null){
              if (this.getDebugSymbols && !cachedAssembly.reader.getDebugSymbols && !cachedAssembly.reader.getDebugSymbolsFailed)
                cachedAssembly.SetupDebugReader(null);
              this.Dispose();
            }
            return cachedAssembly;
          }
          lock (Reader.StaticAssemblyCache) {
            Reader.StaticAssemblyCache[assemblyStrongName] = assembly;
            if (this.fileName != null) {
              Reader.StaticAssemblyCache[this.fileName] = assembly;
            }
          }
        }else{
          cachedAssembly = this.localAssemblyCache[assemblyStrongName] as AssemblyNode;
          if (cachedAssembly != null) {
            if (assembly.FileLastWriteTimeUtc > cachedAssembly.FileLastWriteTimeUtc &&
              assembly.Location != null && cachedAssembly.Location != null && assembly.Location == cachedAssembly.Location) {
              this.localAssemblyCache[assemblyStrongName] = assembly;
              return null;
            }
            if (cachedAssembly.reader != this && cachedAssembly.reader != null) {
#if !ROTOR
              if (this.getDebugSymbols && cachedAssembly.reader.debugReader == null && !cachedAssembly.reader.getDebugSymbolsFailed)
                cachedAssembly.SetupDebugReader(null);
#endif
              this.Dispose();
            }
            return cachedAssembly;
          }
          this.localAssemblyCache[assemblyStrongName] = assembly;
          if (this.fileName != null) this.localAssemblyCache[this.fileName] = assembly;
        }
      }
      return null;
    }
#if !MinimalReader
    internal Module ReadModule()
    {
      return ReadModule(null);
    }
    internal Module ReadModule(AssemblyNode.PostAssemblyLoadProcessor postLoadEvent){
#else
    internal Module ReadModule(){
#endif
      try{
        if (this.fileName != null){
          if (!System.IO.File.Exists(this.fileName)) return null;
          AssemblyNode cachedAssembly;
          if (this.useStaticCache) {
            cachedAssembly = Reader.StaticAssemblyCache[this.fileName] as AssemblyNode;
            if (cachedAssembly != null && cachedAssembly.FileLastWriteTimeUtc == System.IO.File.GetLastWriteTimeUtc(this.fileName)) {
              this.Dispose();
              return cachedAssembly;
            }
          }
          cachedAssembly = this.localAssemblyCache[this.fileName] as AssemblyNode;
          if (cachedAssembly != null && cachedAssembly.FileLastWriteTimeUtc == System.IO.File.GetLastWriteTimeUtc(this.fileName)) {
            this.Dispose();
            return cachedAssembly;
          }
        }
        this.SetupReader();
        if (this.tables.AssemblyTable.Length > 0)
#if !MinimalReader
          return this.ReadAssembly(postLoadEvent);
#else
          return this.ReadAssembly();
#endif
        Module module = this.module = new Module(new Module.TypeNodeProvider(this.GetTypeFromName), 
          new Module.TypeNodeListProvider(this.GetTypeList), new Module.CustomAttributeProvider(this.GetCustomAttributesFor),
          new Module.ResourceProvider(this.GetResources));
        module.reader = this;
        this.ReadModuleProperties(module);
        this.module = module;
        this.ReadAssemblyReferences(module);
        this.ReadModuleReferences(module);
        if (this.getDebugSymbols) this.SetupDebugReader(this.fileName, null);
        return module;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return null;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return module;
      }
#else
      }finally{}
#endif
    }
    private void ReadModuleProperties(Module/*!*/ module){
      ModuleRow[] mods = this.tables.ModuleTable;
      if (mods.Length != 1) throw new InvalidMetadataException(ExceptionStrings.InvalidModuleTable);
      ModuleRow mrow = mods[0];
      module.reader = this;
      module.DllCharacteristics = this.tables.dllCharacteristics;
      module.FileAlignment = this.tables.fileAlignment;
      module.HashValue = this.tables.HashValue;
      module.Kind = this.tables.moduleKind;
      module.Location = this.fileName;
      module.TargetRuntimeVersion = this.tables.targetRuntimeVersion;
      module.LinkerMajorVersion = this.tables.linkerMajorVersion;
      module.LinkerMinorVersion = this.tables.linkerMinorVersion;
      module.MetadataFormatMajorVersion = this.tables.metadataFormatMajorVersion;
      module.MetadataFormatMinorVersion = this.tables.metadataFormatMinorVersion;
      module.Name = this.tables.GetString(mrow.Name);
      module.Mvid = this.tables.GetGuid(mrow.Mvid);
      module.PEKind = this.tables.peKind;
      module.TrackDebugData = this.tables.TrackDebugData;
    }
    private void ReadAssemblyProperties(AssemblyNode/*!*/ assembly) {
      AssemblyRow assemblyRow = this.tables.AssemblyTable[0];
      assembly.HashAlgorithm = (AssemblyHashAlgorithm)assemblyRow.HashAlgId;
      assembly.Version = new System.Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber);
      assembly.Flags = (AssemblyFlags)assemblyRow.Flags;
      assembly.PublicKeyOrToken = this.tables.GetBlob(assemblyRow.PublicKey);
      assembly.ModuleName = assembly.Name;
      assembly.Name = this.tables.GetString(assemblyRow.Name);
      assembly.Culture = this.tables.GetString(assemblyRow.Culture);
      if (this.fileName != null){
        assembly.FileLastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(this.fileName);
      }
      assembly.ContainingAssembly = assembly;
    }
    private void ReadAssemblyReferences(Module/*!*/ module) {
      AssemblyRefRow[] assems = this.tables.AssemblyRefTable;
      int n = assems.Length;
      AssemblyReferenceList assemblies = module.AssemblyReferences = new AssemblyReferenceList(n);
      for (int i = 0; i < n; i++){
        AssemblyRefRow arr = assems[i];
        AssemblyReference assemRef = new AssemblyReference();
        assemRef.Version = new System.Version(arr.MajorVersion, arr.MinorVersion, arr.BuildNumber, arr.RevisionNumber);
        assemRef.Flags = (AssemblyFlags)arr.Flags;
        assemRef.PublicKeyOrToken = this.tables.GetBlob(arr.PublicKeyOrToken);
        assemRef.Name = this.tables.GetString(arr.Name);
        //if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assemRef.Name && 
        //  assemRef.Version > CoreSystemTypes.SystemAssembly.Version){
        //  HandleError(module, ExceptionStrings.ModuleOrAssemblyDependsOnMoreRecentVersionOfCoreLibrary);
        //}
        assemRef.Culture = this.tables.GetString(arr.Culture);
        if (assemRef.Culture != null && assemRef.Culture.Length == 0) assemRef.Culture = null;
        assemRef.HashValue = this.tables.GetBlob(arr.HashValue);
        assemRef.Reader = this;
        assems[i].AssemblyReference = assemRef;
        assemblies.Add(assemRef);
      }
    }
    private void ReadModuleReferences(Module/*!*/ module) {
      FileRow[] files = this.tables.FileTable;
      ModuleRefRow[] modRefs = this.tables.ModuleRefTable;
      int n = modRefs.Length;
      ModuleReferenceList modules = module.ModuleReferences = new ModuleReferenceList(n);
      for (int i = 0; i < n; i++){
        Module mod;
        int nameIndex = modRefs[i].Name;
        string name = this.tables.GetString(nameIndex);
        string dir = BetterPath.GetDirectoryName(this.module.Location);
        string location = BetterPath.Combine(dir, name);
        for (int j = 0, m = files == null ? 0 : files.Length; j < m; j++){
          if (files[j].Name != nameIndex) continue;
          if ((files[j].Flags & (int)FileFlags.ContainsNoMetaData) == 0)
            mod = Module.GetModule(location, this.doNotLockFile, this.getDebugSymbols, false);
          else
            mod = null;
          if (mod == null){
            mod = new Module();
            mod.Name = name;
            mod.Location = location;
            mod.Kind = ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary;
          }
          mod.HashValue = this.tables.GetBlob(files[j].HashValue);
          mod.ContainingAssembly = module.ContainingAssembly;
          modRefs[i].Module = mod;
          modules.Add(new ModuleReference(name, mod));
          goto nextModRef;
        }        
        mod = new Module();
        mod.Name = name;
        mod.Kind = ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary;
        if (System.IO.File.Exists(location)) mod.Location = location;
        mod.ContainingAssembly = module.ContainingAssembly;
        modRefs[i].Module = mod;
        modules.Add(new ModuleReference(name, mod));
      nextModRef:;
      }
    }
    private static string ReadSerString(MemoryCursor/*!*/ sigReader) {
      int n = sigReader.ReadCompressedInt();
      if (n < 0) return null;
      return sigReader.ReadUTF8(n);
    }
    private void AddFieldsToType(TypeNode/*!*/ type, FieldRow[]/*!*/ fieldDefs, FieldPtrRow[]/*!*/ fieldPtrs, int start, int end) {
      for (int i = start; i < end; i++){
        int ii = i;
        if (fieldPtrs.Length > 0) ii = fieldPtrs[i-1].Field;
        Field field = this.GetFieldFromDef(ii, type);
        if (field != null) type.Members.Add(field);
      }
    }
    private void GetUnderlyingTypeOfEnumNode(EnumNode /*!*/enumNode, FieldRow[]/*!*/ fieldDefs, FieldPtrRow[]/*!*/ fieldPtrs, int start, int end) {
      TypeNode underlyingType = null;
      for (int i = start; i < end; i++){
        int ii = i;
        if (fieldPtrs.Length > 0) ii = fieldPtrs[i-1].Field;
        FieldRow fld = fieldDefs[ii-1];
        if (fld.Field != null && !fld.Field.IsStatic){
          underlyingType = fld.Field.Type;
          break;
        }
        FieldFlags fieldFlags = (FieldFlags)fld.Flags;
        if ((fieldFlags & FieldFlags.Static) == 0){
          this.tables.GetSignatureLength(fld.Signature);
          MemoryCursor sigReader = this.tables.GetNewCursor();          
          GetAndCheckSignatureToken(6, sigReader);
          underlyingType = this.ParseTypeSignature(sigReader);
          break;
        }
      }
      enumNode.underlyingType = underlyingType;
    }
    private void AddMethodsToType(TypeNode/*!*/ type, MethodPtrRow[]/*!*/ methodPtrs, int start, int end)
      //^ requires type.members != null;
    {
      for (int i = start; i < end; i++){
        int ii = i;
        if (methodPtrs.Length > 0) ii = methodPtrs[i-1].Method;
        Method method = this.GetMethodFromDef(ii, type);
        if (method != null && ((method.Flags & MethodFlags.RTSpecialName) == 0 || method.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey))
          type.members.Add(method);
      }
    }
    private void AddMoreStuffToParameters(Method method, ParameterList parameters, int start, int end) {
      ParamRow[] pars = this.tables.ParamTable;
      int n = parameters == null ? 0 : parameters.Count;
      for (int i = start; i < end; i++){
        ParamRow pr = pars[i-1];
        if (pr.Sequence == 0 && method != null){
          //The parameter entry with sequence 0 is used as a target for custom attributes that apply to the return value
          method.ReturnAttributes = this.GetCustomAttributesFor((i << 5)|4);
          if ((pr.Flags & (int)ParameterFlags.HasFieldMarshal) != 0)
            method.ReturnTypeMarshallingInformation = this.GetMarshallingInformation((i << 1)|1);
          this.AddMoreStuffToParameters(null, parameters, start+1, end); 
          return;
        }
        int j = pr.Sequence;
        if (j < 1 || j > n) continue; //Bad metadata, ignore
        if (parameters == null) continue;
        Parameter par = parameters[j-1];
        par.Attributes = this.GetCustomAttributesFor((i << 5)|4);
        par.Flags = (ParameterFlags)pr.Flags;
        if ((par.Flags & ParameterFlags.HasDefault) != 0) 
          par.DefaultValue = this.GetLiteral((i << 2)|1, par.Type);
        if ((par.Flags & ParameterFlags.HasFieldMarshal) != 0)
          par.MarshallingInformation = this.GetMarshallingInformation((i << 1)|1);
        par.Name = tables.GetIdentifier(pr.Name);
#if ExtendedRuntime
        for (int k = 0, al = par.Attributes == null ? 0 : par.Attributes.Count; k < al; k++) {
          if (par.Attributes[k].Type == ExtendedRuntimeTypes.NotNullAttribute) {
            Reference r = par.Type as Reference;
            if (r != null){
              // need to make it a reference to a non-null type and not a non-null wrapper around the reference
              // also *must* make it a new Reference.
              OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, r.ElementType);
              par.Type = om.GetReferenceType();
            }else{
              par.Type = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, par.Type);
            }
            // Someone putting an attribute directly on the "real" method is still a
            // kind of out-of-band contract.
            // This marking is the way to signal that any override or implementing method being compiled
            // should not have its non-null annotations persisted as optional modifiers.
            par.DeclaringMethod.HasOutOfBandContract = true;
          } else if (par.Attributes[k].Type == ExtendedRuntimeTypes.NotNullArrayElementsAttribute) {
            Stack s = new Stack();
            Reference r = par.Type as Reference;
            TypeNode t;
            if (r != null) {
              // need to make it a reference to an array of non-null type and not a non-null wrapper around the reference
              t = r.ElementType;
            }
            else {
              t = par.Type;
            }
            while (t is OptionalModifier) {
              OptionalModifier om = t as OptionalModifier;
              s.Push(om.Modifier);
              t = om.ModifiedType;
            }
            ArrayType at = t as ArrayType;
            if (at != null) { // just silently ignore if attribute is on a non-array type?
              TypeNode newTypeForParameter;
              OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, at.ElementType);
              while (0 < s.Count) {
                om = OptionalModifier.For((TypeNode)s.Pop(), om);
              }
              // also *must* make it a new array type, can't set the ElementType.
              newTypeForParameter = om.GetArrayType(1);
              if (r != null) {
                // also *must* make it a new Reference, can't set the ElementType.
                newTypeForParameter = newTypeForParameter.GetReferenceType();
              }
              par.Type = newTypeForParameter;
              // Someone putting an attribute directly on the "real" method is still a
              // kind of out-of-band contract.
              // This marking is the way to signal that any override or implementing method being compiled
              // should not have its non-null annotations persisted as optional modifiers.
              par.DeclaringMethod.HasOutOfBandContract = true;
            }
          }
        }
#endif
      }
    }
    private void AddPropertiesToType(TypeNode/*!*/ type, PropertyRow[]/*!*/ propertyDefs, PropertyPtrRow[]/*!*/ propertyPtrs, int start, int end) 
      //requires type.members != null;
    {
      MetadataReader tables = this.tables;
      for (int i = start; i < end; i++){
        int ii = i;
        if (propertyPtrs.Length > 0) ii = propertyPtrs[i-1].Property;
        PropertyRow prop = propertyDefs[ii-1];
        Property property = new Property();
        property.Attributes = this.GetCustomAttributesFor((ii << 5)|9);
        property.DeclaringType = type;
        property.Flags = (PropertyFlags)prop.Flags;
        property.Name = tables.GetIdentifier(prop.Name);
        if ((property.Flags & PropertyFlags.RTSpecialName) == 0 || property.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey){
          this.AddMethodsToProperty(ii, property);
          type.members.Add(property);
        }
        //REVIEW: the signature seems to be redundant. Is there any point in retrieving it?
      }
    }
    private void AddMethodsToProperty(int propIndex, Property/*!*/ property) {
      int codedPropIndex = (propIndex << 1) | 1;
      MetadataReader tables = this.tables;
      MethodRow[] methods = tables.MethodTable;
      MethodSemanticsRow[] methodSemantics = tables.MethodSemanticsTable;
      int i = 0, n = methodSemantics.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodSemantics) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (methodSemantics[k].Association < codedPropIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && methodSemantics[i-1].Association == codedPropIndex) i--;
      }
      for (; i < n; i++){
        MethodSemanticsRow meth = methodSemantics[i];
        Method propertyMethod = methods[meth.Method-1].Method;
        if (propertyMethod == null) continue;
        if (meth.Association == codedPropIndex){
          propertyMethod.DeclaringMember = property;
          switch(meth.Semantics){
            case 0x0001 : property.Setter = propertyMethod; break;
            case 0x0002 : property.Getter = propertyMethod; break;
            default:
              if (property.OtherMethods == null) property.OtherMethods = new MethodList();
              property.OtherMethods.Add(propertyMethod); break;
          }
        }else if (sorted)
          break;
      }
    }
    private void AddEventsToType(TypeNode/*!*/ type, EventRow[]/*!*/ eventDefs, EventPtrRow[]/*!*/ eventPtrs, int start, int end) {
      MetadataReader tables = this.tables;
      for (int i = start; i < end; i++){
        int ii = i;
        if (eventPtrs.Length > 0) ii = eventPtrs[i].Event;
        EventRow ev = eventDefs[ii-1];
        Event evnt = new Event();
        evnt.Attributes = this.GetCustomAttributesFor((ii << 5)|10);
        evnt.DeclaringType = type;
        evnt.Flags = (EventFlags)ev.Flags;
        evnt.HandlerType = this.DecodeAndGetTypeDefOrRefOrSpec(ev.EventType);
        evnt.Name = tables.GetIdentifier(ev.Name);
        if ((evnt.Flags & EventFlags.RTSpecialName) == 0 || evnt.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey){
          this.AddMethodsToEvent(ii, evnt);
          type.Members.Add(evnt);
        }
      }
    }
    private void AddMethodsToEvent(int eventIndex, Event/*!*/ evnt) {
      int codedEventIndex = eventIndex << 1;
      MetadataReader tables = this.tables;
      MethodRow[] methods = tables.MethodTable;
      MethodSemanticsRow[] methodSemantics = tables.MethodSemanticsTable;
      int i = 0, n = methodSemantics.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodSemantics) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (methodSemantics[k].Association < codedEventIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && methodSemantics[i-1].Association == codedEventIndex) i--;
      }
      MethodFlags handlerFlags = (MethodFlags)0;
      for (; i < n; i++){
        MethodSemanticsRow meth = methodSemantics[i];
        Method eventMethod = methods[meth.Method-1].Method;
        if (eventMethod == null) continue;
        if (meth.Association == codedEventIndex){
          eventMethod.DeclaringMember = evnt;
          switch(meth.Semantics){
            case 0x0008: evnt.HandlerAdder = eventMethod; handlerFlags = eventMethod.Flags; break;
            case 0x0010: evnt.HandlerRemover = eventMethod; handlerFlags = eventMethod.Flags; break;
            case 0x0020: evnt.HandlerCaller = eventMethod; break;
            default:
              if (evnt.OtherMethods == null) evnt.OtherMethods = new MethodList();
              evnt.OtherMethods.Add(eventMethod); break;
          }
        }else if (sorted)
          break;
      }
      evnt.HandlerFlags = handlerFlags;
    }
    private bool TypeDefOrRefOrSpecIsClass(int codedIndex){
      if (codedIndex == 0) return false;
      switch(codedIndex & 0x3){
        case 0x00 : return this.TypeDefIsClass(codedIndex >> 2);
        case 0x01 : TypeNode t = this.GetTypeFromRef(codedIndex >> 2); return t is Class;
        case 0x02 : return this.TypeSpecIsClass(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
    private bool TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(int codedIndex){
      if (codedIndex == 0) return false;
      switch (codedIndex & 0x3) {
        case 0x00: return this.TypeDefIsClassButNotValueTypeBaseClass(codedIndex >> 2);
        case 0x01: 
          TypeNode t = this.GetTypeFromRef(codedIndex >> 2); 
          return t != CoreSystemTypes.ValueType && t != CoreSystemTypes.Enum && t is Class;
        case 0x02: return this.TypeSpecIsClass(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
    private TypeNode DecodeAndGetTypeDefOrRefOrSpec(int codedIndex) {
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2);
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2);
        case 0x02 : return this.GetTypeFromSpec(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
    private TypeNode DecodeAndGetTypeDefOrRefOrSpec(int codedIndex, bool expectStruct) {
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2);
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, expectStruct);
        case 0x02 : return this.GetTypeFromSpec(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
#if ExtendedRuntime
    private Interface GetInterfaceIfNotGenericInstance(int codedIndex){
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2) as Interface;
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, false) as Interface;
      }
      return null;
    }
#endif
    private TypeNode GetTypeIfNotGenericInstance(int codedIndex){
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2);
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, false);
      }
      return null;
    }
    internal AssemblyNode/*!*/ GetAssemblyFromReference(AssemblyReference/*!*/ assemblyReference) {
      lock (Module.GlobalLock) {
        if (SystemAssemblyLocation.ParsedAssembly != null && (assemblyReference.Name == "mscorlib" || assemblyReference.Name == "basetypes" || assemblyReference.Name == "ioconfig"
          || assemblyReference.Name == "singularity.v1" )) 
          return SystemAssemblyLocation.ParsedAssembly;
        if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assemblyReference.Name) return CoreSystemTypes.SystemAssembly;
        string strongName = null;
        object cachedValue = null;
        if (assemblyReference.PublicKeyOrToken == null || assemblyReference.PublicKeyOrToken.Length == 0){
          if (assemblyReference.Location != null)
            cachedValue = this.localAssemblyCache[assemblyReference.Location];
          if (cachedValue == null){
            cachedValue = this.localAssemblyCache[assemblyReference.Name];
            if (cachedValue != null && assemblyReference.Location != null)
              this.localAssemblyCache[assemblyReference.Location] = cachedValue;
          }
        }else{
          strongName = assemblyReference.StrongName;
          if (this.useStaticCache){
            //See if reference is to an assembly that lives in the GAC.
            if (assemblyReference.Location != null)
              cachedValue = Reader.StaticAssemblyCache[assemblyReference.Location];
            if (cachedValue == null)
              cachedValue = Reader.StaticAssemblyCache[strongName];
          }
          if (cachedValue == null)
            cachedValue = this.localAssemblyCache[strongName];
        }
        if (cachedValue == null){
          //See if assembly is a platform assembly (and apply unification)
          AssemblyReference aRef = (AssemblyReference)TargetPlatform.AssemblyReferenceFor[Identifier.For(assemblyReference.Name).UniqueIdKey];
          if (aRef != null && assemblyReference.Version != null && aRef.Version >= assemblyReference.Version && aRef.MatchesIgnoringVersion(assemblyReference)){
            AssemblyNode platformAssembly = aRef.assembly;
            if (platformAssembly == null){
              Debug.Assert(aRef.Location != null);
#if MinimalReader
              platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
              platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            }
            if (platformAssembly != null){
              if (strongName == null) strongName = assemblyReference.Name;
              lock (Reader.StaticAssemblyCache) {
                if (aRef.Location != null)
                  Reader.StaticAssemblyCache[aRef.Location] = platformAssembly;
                Reader.StaticAssemblyCache[strongName] = platformAssembly;
              }
              aRef.assembly = platformAssembly;
              return platformAssembly;
            }
          }
        }
        AssemblyNode assembly = cachedValue as AssemblyNode;
        if (assembly != null) goto done;
      
        //No cached assembly and no cached reader for this assembly. Look for a resolver.
        if (this.module != null){
          assembly = this.module.Resolve(assemblyReference);
          if (assembly != null){
            if (strongName == null){
              this.localAssemblyCache[assembly.Name] = assembly;
              if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
            }else{
              if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assembly.Name) return CoreSystemTypes.SystemAssembly;
              lock (Reader.StaticAssemblyCache) {
                if (this.useStaticCache) {
                  if (assembly.Location != null)
                    Reader.StaticAssemblyCache[assembly.Location] = assembly;
                  Reader.StaticAssemblyCache[strongName] = assembly;
                } else {
                  this.localAssemblyCache[strongName] = assembly;
                  if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
                }
              }
            }
            goto done;
          }
        }

        //Look for an assembly with the given name in the same directory as the referencing module
        if (this.directory != null){
          string fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".dll");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".exe");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".winmd");
          if (System.IO.File.Exists(fileName)) {
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null) {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }
          }
          fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".ill");
          if (System.IO.File.Exists(fileName)) {
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }
          }
        }
        //Look for an assembly in the same directory as the application using Reader.
        { string fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name+".dll");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name+".exe");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name+".winmd");
          if (System.IO.File.Exists(fileName)) {
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null) {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }
          }
        }
        assembly = null;

        //Probe the GAC
#if FxCop
        if(probeGAC){
#endif
        string gacLocation = null;
        if (strongName != null){
#if !ROTOR
          //Look for the assembly in the system's Global Assembly Cache
          gacLocation = GlobalAssemblyCache.GetLocation(assemblyReference);
          if (gacLocation != null && gacLocation.Length == 0) gacLocation = null;
#else
          //TODO: look in the ROTOR GAC
#endif
          if (gacLocation != null){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(gacLocation, this.useStaticCache ? Reader.StaticAssemblyCache : this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(gacLocation, this.useStaticCache ? Reader.StaticAssemblyCache : this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              lock (Reader.StaticAssemblyCache) {
                if (this.useStaticCache) {
                  Reader.StaticAssemblyCache[gacLocation] = assembly;
                  Reader.StaticAssemblyCache[strongName] = assembly;
                } else {
                  this.localAssemblyCache[gacLocation] = assembly;
                  this.localAssemblyCache[strongName] = assembly;
                }
              }
            }
          }
        }
#if FxCop
        }
#endif
        goto done;
      cacheIt:
        if (strongName == null){
          this.localAssemblyCache[assembly.Name] = assembly;
          if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
        }else{
          this.localAssemblyCache[strongName] = assembly;
          if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
        }
#if !MinimalReader
        // the post load event should fire when we load the assembly the first time
//        assembly.InitializePostAssemblyLoadAndFire(this.module);
#endif
      done:
        if (assembly != null)
          assembly.InitializeAssemblyReferenceResolution(this.module);
        if (assembly == null){
          if (this.module != null) {
            assembly = this.module.ResolveAfterProbingFailed(assemblyReference);
            if (assembly != null) goto cacheIt;
            HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.AssemblyReferenceNotResolved, assemblyReference.StrongName));
          }
          assembly = new AssemblyNode();
          assembly.Culture = assemblyReference.Culture;
          assembly.Name = assemblyReference.Name;
          assembly.PublicKeyOrToken = assemblyReference.PublicKeyOrToken;
          assembly.Version = assemblyReference.Version;
          assembly.Location = "unknown:location";
          goto cacheIt;
        }
        return assembly;
      }
    }
#if !MinimalReader
    private AssemblyNode.PostAssemblyLoadProcessor ReferringAssemblyPostLoad
    {
      get
      {
        AssemblyNode assem = this.module as AssemblyNode;
        if (assem == null) return null;
        return assem.GetAfterAssemblyLoad();
      }
    }
#endif
    private static void GetAndCheckSignatureToken(int expectedToken, MemoryCursor/*!*/ sigReader) {
      int tok = sigReader.ReadCompressedInt();
      if (tok != expectedToken) throw new InvalidMetadataException(ExceptionStrings.MalformedSignature);
    }
    private Method GetConstructorDefOrRef(int codedIndex, out TypeNodeList varArgTypes) {
      varArgTypes = null;
      switch(codedIndex & 0x7){
        case 0x02 : return this.GetMethodFromDef(codedIndex >> 3); 
        case 0x03 : return (Method)this.GetMemberFromRef(codedIndex >> 3, out varArgTypes);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
    }
    private void GetResources(Module/*!*/ module) {
      ManifestResourceRow[] manifestResourceTable = this.tables.ManifestResourceTable;
      int n = manifestResourceTable.Length; 
      ResourceList resources = new ResourceList(n);
      for (int i = 0; i < n; i++){
        ManifestResourceRow mrr = manifestResourceTable[i];
        Resource r = new Resource();
        r.Name = this.tables.GetString(mrr.Name);
        r.IsPublic = (mrr.Flags&7) == 1;
        int impl = mrr.Implementation;
        if (impl != 0){
          switch(impl & 0x3){
            case 0x0: 
              string modName = this.tables.GetString(this.tables.FileTable[(impl >> 2)-1].Name);
              if ((this.tables.FileTable[(impl >> 2)-1].Flags & (int)FileFlags.ContainsNoMetaData) != 0){
                r.DefiningModule = new Module();
                r.DefiningModule.Directory = module.Directory;
                r.DefiningModule.Location = Path.Combine(module.Directory,modName);
                r.DefiningModule.Name = modName;
                r.DefiningModule.Kind = ModuleKindFlags.ManifestResourceFile;
                r.DefiningModule.ContainingAssembly = module.ContainingAssembly;
                r.DefiningModule.HashValue = this.tables.GetBlob(this.tables.FileTable[(impl >> 2) - 1].HashValue);
              } else {
                string modLocation = modName;
                r.DefiningModule = GetNestedModule(module, modName, ref modLocation);
              }
              break;
            case 0x1: 
              r.DefiningModule = this.tables.AssemblyRefTable[(impl >> 2)-1].AssemblyReference.Assembly;
              break;
          }
        }else{
          r.DefiningModule = module;
          r.Data = this.tables.GetResourceData(mrr.Offset);
        }
        resources.Add(r);
      }
      module.Resources = resources;
      module.Win32Resources = this.tables.ReadWin32Resources();
    }
    private SecurityAttribute GetSecurityAttribute(int i){
      DeclSecurityRow dsr = this.tables.DeclSecurityTable[i];
      SecurityAttribute attr = new SecurityAttribute();
      attr.Action = (System.Security.Permissions.SecurityAction)dsr.Action;
      if (this.module.MetadataFormatMajorVersion > 1 || this.module.MetadataFormatMinorVersion > 0){
        attr.PermissionAttributes = this.GetPermissionAttributes(dsr.PermissionSet, attr.Action);
        if (attr.PermissionAttributes != null) return attr;
      }
      attr.SerializedPermissions = (string)this.tables.GetBlobString(dsr.PermissionSet);
      return attr;
    }
    private AttributeList GetPermissionAttributes(int blobIndex, System.Security.Permissions.SecurityAction action){
      AttributeList result = new AttributeList();
      int blobLength;
      MemoryCursor sigReader = this.tables.GetBlobCursor(blobIndex, out blobLength);
      if (blobLength == 0) return null;
      byte header = sigReader.ReadByte();
      if (header != (byte)'*'){
        if (header == (byte)'<') return null;
        if (header == (byte)'.') return this.GetPermissionAttributes2(blobIndex, action);
        HandleError(this.module, ExceptionStrings.BadSecurityPermissionSetBlob);
        return null;
      }
      sigReader.ReadInt32(); //Skip over the token for the attribute target
      sigReader.ReadInt32(); //Skip over the security action
      int numAttrs = sigReader.ReadInt32();
      for (int i = 0; i < numAttrs; i++)
        result.Add(this.GetPermissionAttribute(sigReader));
      return result;
    }
    private AttributeNode GetPermissionAttribute(MemoryCursor/*!*/ sigReader) {
      sigReader.ReadInt32(); //Skip over index
      int typeNameLength = sigReader.ReadInt32();
      sigReader.ReadUTF8(typeNameLength); //Skip over type name
      int constructorToken = sigReader.ReadInt32();
      sigReader.ReadInt32(); //Skip over attribute type token
      sigReader.ReadInt32(); //Skip over assembly ref token
      int caBlobLength = sigReader.ReadInt32();
      sigReader.ReadInt32(); //Skip over the number of parameters in the CA blob
      TypeNodeList varArgTypes; //Ignored because vararg constructors are not allowed in Custom Attributes
      Method cons = this.GetConstructorDefOrRef(constructorToken, out varArgTypes);
      if (cons == null) cons = new Method();
      return this.GetCustomAttribute(cons, sigReader, caBlobLength);
    }
    private AttributeList GetPermissionAttributes2(int blobIndex, System.Security.Permissions.SecurityAction action){
      AttributeList result = new AttributeList();
      int blobLength;
      MemoryCursor sigReader = this.tables.GetBlobCursor(blobIndex, out blobLength);
      if (blobLength == 0) return null;
      byte header = sigReader.ReadByte();
      if (header != (byte)'.'){
        HandleError(this.module, ExceptionStrings.BadSecurityPermissionSetBlob);
        return null;
      }
      int numAttrs = sigReader.ReadCompressedInt();
      for (int i = 0; i < numAttrs; i++)
        result.Add(this.GetPermissionAttribute2(sigReader, action));
      return result;
    }
    private AttributeNode GetPermissionAttribute2(MemoryCursor/*!*/ sigReader, System.Security.Permissions.SecurityAction action) {
      int typeNameLength = sigReader.ReadCompressedInt();
      string serializedTypeName = sigReader.ReadUTF8(typeNameLength);
      TypeNode attrType = null;
      try{
        attrType = this.GetTypeFromSerializedName(serializedTypeName);
      }catch(InvalidMetadataException){}
      if (attrType == null){
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveType,serializedTypeName));
        return null;
      }
      InstanceInitializer cons = attrType.GetConstructor(CoreSystemTypes.SecurityAction);
      if (cons == null){
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture, 
        ExceptionStrings.SecurityAttributeTypeDoesNotHaveADefaultConstructor, serializedTypeName));
        return null;
      }
      sigReader.ReadCompressedInt(); //caBlobLength
      int numProps = sigReader.ReadCompressedInt(); //Skip over the number of properties in the CA blob
      ExpressionList arguments = new ExpressionList(numProps+1);
      arguments.Add(new Literal(action, CoreSystemTypes.SecurityAction));
      this.GetCustomAttributeNamedArguments(arguments, (ushort)numProps, sigReader);
      return new AttributeNode(new MemberBinding(null, cons), arguments);
    }
    private static void HandleError(Module mod, string errorMessage){
#if !FxCop
      if (mod != null && (mod.ContainingAssembly == null || (mod.ContainingAssembly.Flags & AssemblyFlags.ContainsForeignTypes) == 0)){
        if (mod.MetadataImportErrors == null) mod.MetadataImportErrors = new ArrayList();
        mod.MetadataImportErrors.Add(new InvalidMetadataException(errorMessage));
      }
#else
      throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.ModuleError, mod.Name, errorMessage));
#endif
    }
    private AttributeNode GetCustomAttribute(int i){
      CustomAttributeRow ca = this.tables.CustomAttributeTable[i];
      TypeNodeList varArgTypes; //Ignored because vararg constructors are not allowed in Custom Attributes
      Method cons = this.GetConstructorDefOrRef(ca.Constructor, out varArgTypes);
      if (cons == null) cons = new Method();
      int blobLength;
      MemoryCursor sigReader = this.tables.GetBlobCursor(ca.Value, out blobLength);
      return this.GetCustomAttribute(cons, sigReader, blobLength);
    }
    private AttributeNode GetCustomAttribute(Method/*!*/ cons, MemoryCursor/*!*/ sigReader, int blobLength) {
      AttributeNode attr = new AttributeNode();
      attr.Constructor = new MemberBinding(null, cons);
      int n = cons.Parameters == null ? 0 : cons.Parameters.Count;
      ExpressionList arguments = attr.Expressions = new ExpressionList(n);
      int posAtBlobStart = sigReader.Position;
      sigReader.ReadUInt16(); //Prolog
      for (int j = 0; j < n; j++){
        TypeNode t = TypeNode.StripModifiers(cons.Parameters[j].Type);
        if (t == null) continue;
        TypeNode/*!*/ pt = t;
        object val = null;
        try{
          val = this.GetCustomAttributeLiteralValue(sigReader, ref pt);
#if !FxCop        
        }catch (Exception e){ 
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
#else
        }finally{}
#endif
        Literal lit = val as Literal;
        if (lit == null) lit = new Literal(val, pt);
        arguments.Add(lit);
      }
      if (sigReader.Position+1 < posAtBlobStart + blobLength){
        ushort numNamed = sigReader.ReadUInt16();
        this.GetCustomAttributeNamedArguments(arguments, numNamed, sigReader);
      }
      return attr;
    }
    private void GetCustomAttributeNamedArguments(ExpressionList/*!*/ arguments, ushort numNamed, MemoryCursor/*!*/ sigReader) {
      for (int j = 0; j < numNamed; j++){
        int nameTag = sigReader.ReadByte();
        bool mustBox = sigReader.Byte(0) == (byte)ElementType.BoxedEnum;
        TypeNode/*!*/ vType = this.ParseTypeSignature(sigReader);
        Identifier id = sigReader.ReadIdentifierFromSerString();
        object val = this.GetCustomAttributeLiteralValue(sigReader, ref vType);
        Literal lit = val as Literal;
        if (lit == null) lit = new Literal(val, vType);
        NamedArgument narg = new NamedArgument(id, lit);
        narg.Type = vType;
        narg.IsCustomAttributeProperty = nameTag == 0x54;
        narg.ValueIsBoxed = mustBox;
        arguments.Add(narg);
      }
    }
    private object GetCustomAttributeLiteralValue(MemoryCursor/*!*/ sigReader, TypeNode/*!*/ type) {
      TypeNode/*!*/ t = type;
      object result = this.GetCustomAttributeLiteralValue(sigReader, ref t);
      EnumNode enumType = t as EnumNode;
      if (enumType != null && type == CoreSystemTypes.Object) result = new Literal(result, enumType);
      else if (type == CoreSystemTypes.Object && t != CoreSystemTypes.Object) {
        Literal lit = result as Literal;
        if (lit == null) result = new Literal(result, t);
      }
      return result;
    }
    private object GetCustomAttributeLiteralValue(MemoryCursor/*!*/ sigReader, ref TypeNode/*!*/ type) {
      if (type == null) return sigReader.ReadInt32();
      switch(type.typeCode){
        case ElementType.Boolean: return sigReader.ReadBoolean();
        case ElementType.Char: return sigReader.ReadChar();
        case ElementType.Double: return sigReader.ReadDouble();
        case ElementType.Single: return sigReader.ReadSingle(); 
        case ElementType.Int16: return sigReader.ReadInt16();
        case ElementType.Int32: return sigReader.ReadInt32();
        case ElementType.Int64: return sigReader.ReadInt64();
        case ElementType.Int8: return sigReader.ReadSByte();
        case ElementType.UInt16: return sigReader.ReadUInt16();
        case ElementType.UInt32: return sigReader.ReadUInt32();
        case ElementType.UInt64: return sigReader.ReadUInt64();
        case ElementType.UInt8: return sigReader.ReadByte();
        case ElementType.String: return ReadSerString(sigReader);
        case ElementType.ValueType:
          EnumNode etype = GetCustomAttributeEnumNode(ref type);
          var enumVal = this.GetCustomAttributeLiteralValue(sigReader, etype.UnderlyingType);
#if !MinimalReader
          if (this.module.ContainingAssembly != null && (this.module.ContainingAssembly.Flags & AssemblyFlags.ContainsForeignTypes) != 0) {
            if (etype == SystemTypes.AttributeTargets) {
              switch ((int)enumVal) {
                case 0x00000001: enumVal = 0x00001000; break;
                case 0x00000002: enumVal = 0x00000010; break;
                case 0x00000004: enumVal = 0x00000200; break;
                case 0x00000008: enumVal = 0x00000100; break;
                case 0x00000010: enumVal = 0x00000400; break;
                case 0x00000020: enumVal = 0x00000000; break;
                case 0x00000040: enumVal = 0x00000040; break;
                case 0x00000080: enumVal = 0x00000800; break;
                case 0x00000100: enumVal = 0x00000080; break;
                case 0x00000200: enumVal = 0x00000004; break;
                case 0x00000400: enumVal = 0x00000008; break;
                case 0x00000800: enumVal = 0x00000000; break;
                case -1: enumVal = 0x00007FFF; break;
              }
            }
          }
#endif
          return enumVal;
        case ElementType.Class: return this.GetTypeFromSerializedName(ReadSerString(sigReader));
        case ElementType.SzArray:
          int numElems = sigReader.ReadInt32();
          TypeNode elemType = ((ArrayType)type).ElementType;
          return this.GetCustomAttributeLiteralArray(sigReader, numElems, elemType);
        case ElementType.Object:{
          type = this.ParseTypeSignature(sigReader);
          return this.GetCustomAttributeLiteralValue(sigReader, ref type);
        }
      }
      throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute);
    }
    private static EnumNode/*!*/ GetCustomAttributeEnumNode(ref TypeNode/*!*/ type) {
      EnumNode etype = ((TypeNode)type) as EnumNode;
      if (etype == null || etype.UnderlyingType == null){
        //Happens when type is declared in a assembly that has not been resolved. In that case only the type name
        //and the fact that it is a value type is known. There is no completely safe recovery from it, but at this point we
        //can fake up an enum with Int32 as underlying type. This works in most situations.
        etype = new EnumNode();
        etype.Name = type.Name;
        etype.Namespace = type.Namespace;
        etype.DeclaringModule = type.DeclaringModule;
        etype.UnderlyingType = CoreSystemTypes.Int32;
        type = etype;
      }
      return etype;
    }
    private Array GetCustomAttributeLiteralArray(MemoryCursor/*!*/ sigReader, int numElems, TypeNode/*!*/ elemType) {
      Array array = this.ConstructCustomAttributeLiteralArray(numElems, elemType);
      for (int i = 0; i < numElems; i++) {
        object elem = this.GetCustomAttributeLiteralValue(sigReader, elemType);
        array.SetValue(elem, i);
      }
      return array;
    }
    private Array ConstructCustomAttributeLiteralArray(int numElems, TypeNode/*!*/ elemType) {
      if (numElems == -1) return null;
      if (numElems < 0) throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute);
      switch(elemType.typeCode){
        case ElementType.Boolean: return new Boolean[numElems];
        case ElementType.Char: return new Char[numElems];
        case ElementType.Double: return new Double[numElems];
        case ElementType.Single: return new Single[numElems]; 
        case ElementType.Int16: return new Int16[numElems];
        case ElementType.Int32: return new Int32[numElems];
        case ElementType.Int64: return new Int64[numElems];
        case ElementType.Int8: return new SByte[numElems];
        case ElementType.UInt16: return new UInt16[numElems];
        case ElementType.UInt32: return new UInt32[numElems];
        case ElementType.UInt64: return new UInt64[numElems];
        case ElementType.UInt8: return new Byte[numElems];
        case ElementType.String: return new String[numElems];
        // Only enum value types are legal in attribute instances as stated in section 17.1.3 of the C# 1.0 spec
        case ElementType.ValueType:
          TypeNode/*!*/ elType = elemType;
          EnumNode eType = GetCustomAttributeEnumNode(ref elType);
          return this.ConstructCustomAttributeLiteralArray(numElems, eType.UnderlyingType);
        // This needs to be a TypeNode since GetCustomAttributeLiteralValue will return a Struct if the Type is a value type
        case ElementType.Class: return new TypeNode[numElems];
        // REVIEW: Is this the right exception? Is this the right exception string?
        // Multi-dimensional arrays are not legal in attribute instances according section 17.1.3 of the C# 1.0 spec
        case ElementType.SzArray: throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
        case ElementType.Object: return new Object[numElems];
      }
      throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute);
    }
    //TODO: rewrite this entire mess using a proper grammar based parser
    private TypeNode/*!*/ GetTypeFromSerializedName(string serializedName) {
      if (serializedName == null) return null;
      string assemblyName = null;
      string typeName = serializedName;
      int firstComma = FindFirstCommaOutsideBrackets(serializedName);
      if (firstComma > 0){
        int i = 1;
        while (firstComma+i < serializedName.Length && serializedName[firstComma+i] == ' ') i++;
        assemblyName = serializedName.Substring(firstComma+i);
        typeName = serializedName.Substring(0, firstComma);
      }
      return this.GetTypeFromSerializedName(typeName, assemblyName);
    }
    private static int FindFirstCommaOutsideBrackets(string/*!*/ serializedName) {
      int numBrackets = 0;
      int numAngles = 0;
      for (int i = 0, n = serializedName == null ? 0 : serializedName.Length; i < n; i++){
        char ch = serializedName[i];
        if (ch == '[')
          numBrackets++;
        else if (ch == ']') {
          if (--numBrackets < 0) return -1;
        } else if (ch == '<')
          numAngles++;
        else if (ch == '>') {
          if (--numAngles < 0) return -1;
        } else if (ch == ',' && numBrackets == 0 && numAngles == 0)
          return i;
      }
      return -1;
    }
    private TypeNode/*!*/ GetTypeFromSerializedName(string/*!*/ typeName, string assemblyName) {
      string/*!*/ nspace, name;
      int i;
      ParseTypeName(typeName, out nspace, out name, out i);
      Module tMod = null;
      TypeNode t = this.LookupType(nspace, name, assemblyName, out tMod);
      if (t == null) {
        if (i < typeName.Length && typeName[i] == '!') {
          int codedIndex = 0;
          if (PlatformHelpers.TryParseInt32(typeName.Substring(0, i), out codedIndex)) {
            t = this.DecodeAndGetTypeDefOrRefOrSpec(codedIndex);
            if (t != null) return t;
          }
        }
        t = this.GetDummyTypeNode(Identifier.For(nspace), Identifier.For(name), tMod, null, false);
      }
      if (i >= typeName.Length) return t;
      char ch = typeName[i];
      if (ch == '+') return this.GetTypeFromSerializedName(typeName.Substring(i+1), t);
      if (ch == '&') return t.GetReferenceType();
      if (ch == '*') return t.GetPointerType();
      if (ch == '[') return this.ParseArrayOrGenericType(typeName.Substring(i+1, typeName.Length-1-i), t);
      throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName);
    }
    private TypeNode/*!*/ GetTypeFromSerializedName(string/*!*/ typeName, TypeNode/*!*/ nestingType) {
      string/*!*/ name;
      int i = 0;
      ParseSimpleTypeName(typeName, out name, ref i);
      TypeNode t = nestingType.GetNestedType(Identifier.For(name));
      if (t == null)
        t = this.GetDummyTypeNode(Identifier.Empty, Identifier.For(name), nestingType.DeclaringModule, nestingType, false);
      if (i >= typeName.Length) return t;
      char ch = typeName[i];
      if (ch == '+') return this.GetTypeFromSerializedName(typeName.Substring(i+1), t);
      if (ch == '&') return t.GetReferenceType();
      if (ch == '*') return t.GetPointerType();
      if (ch == '[') return this.ParseArrayOrGenericType(typeName.Substring(i+1, typeName.Length-1-i), t);
      throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName);
    }
    private TypeNode/*!*/ ParseArrayOrGenericType(string typeName, TypeNode/*!*/ rootType) {
      if (typeName == null || rootType == null) { Debug.Assert(false); return rootType; }
      //Get here after "rootType[" has been parsed. What follows is either an array type specifier or some generic type arguments.
      if (typeName.Length == 0)
        throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName); //Something ought to follow the [
      if (typeName[0] == ']'){ //Single dimensional array with zero lower bound
        if (typeName.Length == 1) return rootType.GetArrayType(1);
        if (typeName[1] == '[' && typeName.Length > 2)
          return this.ParseArrayOrGenericType(typeName.Substring(2), rootType.GetArrayType(1));
        throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName);
      }
      if (typeName[0] == '*'){ //Single dimensional array with unknown lower bound
        if (typeName.Length > 1 && typeName[1] == ']'){
          if (typeName.Length == 2) return rootType.GetArrayType(1, true);
          if (typeName[2] == '[' && typeName.Length > 3)
            return this.ParseArrayOrGenericType(typeName.Substring(3), rootType.GetArrayType(1, true));
        }
        throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName);
      }
      if (typeName[0] == ','){ //Muti dimensional array
        int rank = 1;
        while (rank < typeName.Length && typeName[rank] == ',') rank++;
        if (rank < typeName.Length && typeName[rank] == ']') {
          if (typeName.Length == rank+1) return rootType.GetArrayType(rank+1);
          if (typeName[rank+1] == '[' && typeName.Length > rank+2)
            return this.ParseArrayOrGenericType(typeName.Substring(rank+2), rootType.GetArrayType(rank));
        }
        throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName);
      }
      //Generic type instance
      int offset = 0;
      if (typeName[0] == '[') offset = 1; //Assembly qualified type name forming part of a generic parameter list        
      TypeNodeList arguments = new TypeNodeList();
      int commaPos = FindFirstCommaOutsideBrackets(typeName);
      while (commaPos > 1){
        arguments.Add(this.GetTypeFromSerializedName(typeName.Substring(offset, commaPos-offset)));
        typeName = typeName.Substring(commaPos+1);
        offset = typeName[0] == '[' ? 1 : 0;
        commaPos = FindFirstCommaOutsideBrackets(typeName);
      }
      //Find the position of the first unbalanced ].
      int lastCharPos = offset;
      for (int leftBracketCount = 0; lastCharPos < typeName.Length; lastCharPos++) {
        char ch = typeName[lastCharPos];
        if (ch == '[') leftBracketCount++;
        else if (ch == ']') {
          leftBracketCount--;
          if (leftBracketCount < 0) break;
        }
      }
      arguments.Add(this.GetTypeFromSerializedName(typeName.Substring(offset, lastCharPos-offset)));
      TypeNode retVal = rootType.GetGenericTemplateInstance(this.module, arguments);
      if (lastCharPos+1 < typeName.Length && typeName[lastCharPos+1] == ']')
        lastCharPos++;
      if (lastCharPos+1 < typeName.Length) {
        //The generic type is complete, but there is yet more to the type
        char ch = typeName[lastCharPos+1];
        if (ch == '+') retVal = this.GetTypeFromSerializedName(typeName.Substring(lastCharPos+2), retVal);
        if (ch == '&') retVal = retVal.GetReferenceType();
        if (ch == '*') retVal = retVal.GetPointerType();
        if (ch == '[') retVal = this.ParseArrayOrGenericType(typeName.Substring(lastCharPos+2, typeName.Length-1-lastCharPos-1), retVal);
      }
      return retVal;
    }
    private static void ParseSimpleTypeName(string/*!*/ source, out string/*!*/ name, ref int i) {
      int n = source.Length;
      int start = i;
      var sb = new StringBuilder();
      for (; i < n; i++){
        char ch = source[i];
        if (ch == '\\'){ i++; continue;}
        if (ch == '.' || ch == '+' || ch == '&' || ch == '*' || ch == '[' || ch == '!') break;
        sb.Append(ch);
        if (ch == '<'){
          int unmatched = 1;
          while (unmatched > 0 && ++i < n){
            ch = source[i];
            if (ch != '\\') sb.Append(ch); else sb.Append(source[i + 1]);
            if (ch == '\\') i++;
            else if (ch == '<') unmatched++;
            else if (ch == '>') unmatched--;
          }
        }
      }
      name = sb.ToString();
      return;
      if (i < n)
        name = source.Substring(start, i-start);
      else
        name = source.Substring(start);
    }
    private static void ParseTypeName(string/*!*/ source, out string/*!*/ nspace, out string/*!*/ name, out int i) {
      i = 0;
      int n = source.Length;
      nspace = string.Empty;
      while (true){
        int start = i;
        ParseSimpleTypeName(source, out name, ref i);
        if (i < n && source[i] == '.'){i++; continue;}
        if (start != 0) nspace = source.Substring(0, start-1);
        return;
      }      
    }
    private TypeNode LookupType(string/*!*/ nameSpace, string/*!*/ name, string assemblyName, out Module module) {
      Identifier namespaceId = Identifier.For(nameSpace);
      Identifier nameId = Identifier.For(name);
      module = this.module;
      //^ assume module != null;
      if (assemblyName == null) {
        TypeNode t = module.GetType(namespaceId, nameId);
        if (t != null) return t;
        module = CoreSystemTypes.SystemAssembly;
        return CoreSystemTypes.SystemAssembly.GetType(namespaceId, nameId);
      }
      //See if the type is in one of the assemblies explcitly referenced by the current module
      AssemblyReferenceList arefs = module.AssemblyReferences;
      for (int i = 0, n = arefs == null ? 0 : arefs.Count; i < n; i++){
        AssemblyReference aref = arefs[i];
        if (aref != null && aref.StrongName == assemblyName && aref.Assembly != null) {
          module = aref.Assembly;
          return aref.Assembly.GetType(namespaceId, nameId);
        }
      }
      //Construct an assembly reference and probe for it
      AssemblyReference aRef = new AssemblyReference(assemblyName);
      AssemblyNode referringAssembly = this.module as AssemblyNode;
      if (referringAssembly != null && (referringAssembly.Flags & AssemblyFlags.Retargetable) != 0)
        aRef.Flags |= AssemblyFlags.Retargetable;
      AssemblyNode aNode = this.GetAssemblyFromReference(aRef);
      if (aNode != null){
        module = aNode;
        TypeNode result = aNode.GetType(namespaceId, nameId);
        return result;
      }
      return null;
    }
    private void GetCustomAttributesFor(Module/*!*/ module) {
      try{
        if (this.tables.entryPointToken != 0)
          module.EntryPoint = (Method)this.GetMemberFromToken(this.tables.entryPointToken);
        else
          module.EntryPoint = Module.NoSuchMethod;
        if (module.NodeType == NodeType.Module) {
          module.Attributes = this.GetCustomAttributesNonNullFor((1 << 5) | 7);
          return;
        }
        AssemblyNode assembly = (AssemblyNode)module;
        assembly.SecurityAttributes = this.GetSecurityAttributesFor((1 << 2)|2);
        assembly.Attributes = this.GetCustomAttributesNonNullFor((1 << 5) | 14);
        assembly.ModuleAttributes = this.GetCustomAttributesNonNullFor((1 << 5) | 7);
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        module.Attributes = new AttributeList(0);
      }
#else
      }finally{}
#endif
    }
    private AttributeList/*!*/ GetCustomAttributesNonNullFor(int parentIndex) {
      var result = GetCustomAttributesFor(parentIndex);
      if (result != null) return result;
      return new AttributeList(0);
    }
    private AttributeList GetCustomAttributesFor(int parentIndex) {
      CustomAttributeRow[] customAttributes = this.tables.CustomAttributeTable;
      AttributeList attributes = null;
      try{
        int i = 0, n = customAttributes.Length, j = n-1;
        if (n == 0) return null;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.CustomAttribute) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (customAttributes[k].Parent < parentIndex)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && customAttributes[i-1].Parent == parentIndex) i--;
        }
        int count = 0;
        for (int l = i; l < n; l++)
          if (customAttributes[l].Parent == parentIndex)
            count++;
          else if (sorted)
            break;
        if (count > 0) {
          attributes = new AttributeList(count);
        }
        for (; i < n; i++)
          if (customAttributes[i].Parent == parentIndex)
            attributes.Add(this.GetCustomAttribute(i));
          else if (sorted)
            break;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return attributes;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
      }
#else
      }finally{}
#endif
      return attributes;
    }
    private SecurityAttributeList GetSecurityAttributesFor(int parentIndex){
      DeclSecurityRow[] securityAttributes = this.tables.DeclSecurityTable;
      SecurityAttributeList attributes = new SecurityAttributeList();
      try{
        int i = 0, n = securityAttributes.Length, j = n-1;
        if (n == 0) return attributes;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.DeclSecurity) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (securityAttributes[k].Parent < parentIndex)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && securityAttributes[i-1].Parent == parentIndex) i--;
        }
        for (; i < n; i++)
          if (securityAttributes[i].Parent == parentIndex)
            attributes.Add(this.GetSecurityAttribute(i));
          else if (sorted)
            break;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return attributes;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
      }
#else
      }finally{}
#endif
      return attributes;
    }
    private void GetTypeParameterConstraints(int parentIndex, TypeNodeList parameters){
      if (parameters == null) return;
      GenericParamRow[] genericParameters = this.tables.GenericParamTable;
      int i = 0, n = genericParameters.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParam) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameters[k].Owner < parentIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameters[i-1].Owner == parentIndex) i--;
      }
      for (int k = 0; i < n && k < parameters.Count; i++, k++)
        if (genericParameters[i].Owner == parentIndex) {
          TypeNode gp = parameters[k];
          this.GetGenericParameterConstraints(i, ref gp);
          parameters[k] = gp;
        } else if (sorted)
          break;
    }
    private TypeNodeList GetTypeParametersFor(int parentIndex, Member parent){
      GenericParamRow[] genericParameters = this.tables.GenericParamTable;
      TypeNodeList types = new TypeNodeList();
      int i = 0, n = genericParameters.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParam) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameters[k].Owner < parentIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameters[i-1].Owner == parentIndex) i--;
      }
      for (int index = 0; i < n; i++, index++)
        if (genericParameters[i].Owner == parentIndex)
          types.Add(this.GetGenericParameter(i, index, parent));
        else if (sorted)
          break;
      if (types.Count == 0) return null;
      return types;
    }
    private TypeNode GetGenericParameter(int index, int parameterListIndex, Member parent){
      GenericParamRow[] genericParameters = this.tables.GenericParamTable;
      GenericParamRow gpr = genericParameters[index++];
      string name = this.tables.GetString(gpr.Name);
      GenericParamConstraintRow[] genericParameterConstraints = this.tables.GenericParamConstraintTable;
      bool isClass = false;
      int i = 0, n = genericParameterConstraints.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParamConstraint) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameterConstraints[k].Param < index)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameterConstraints[i-1].Param == index) i--;
      }
      for (; i < n && !isClass; i++){
        if (genericParameterConstraints[i].Param == index){
          isClass = this.TypeDefOrRefOrSpecIsClass(genericParameterConstraints[i].Constraint);
        }else if (sorted)
          break;
      }
      if (isClass){
        ClassParameter cp = parent is Method ? new MethodClassParameter() : new ClassParameter();
        cp.DeclaringMember = parent;
        cp.ParameterListIndex = parameterListIndex;
        cp.Name = Identifier.For(name);
        cp.DeclaringModule = this.module;
        cp.TypeParameterFlags = (TypeParameterFlags)gpr.Flags;
        cp.ProvideTypeAttributes = this.GetTypeParameterAttributes;
        cp.ProviderHandle = index;
        return cp;
      }
      TypeParameter tp = parent is Method ? new MethodTypeParameter() : new TypeParameter();
      tp.DeclaringMember = parent;
      tp.ParameterListIndex = parameterListIndex;
      tp.Name = Identifier.For(name);
      tp.DeclaringModule = this.module;
      tp.TypeParameterFlags = (TypeParameterFlags)gpr.Flags;
      tp.ProvideTypeAttributes = this.GetTypeParameterAttributes;
      tp.ProviderHandle = index;
      return tp;
    }
    private void GetGenericParameterConstraints(int index, ref TypeNode/*!*/ parameter) {
      Debug.Assert(parameter != null);
      index++;
      GenericParamConstraintRow[] genericParameterConstraints = this.tables.GenericParamConstraintTable;
      TypeNodeList constraints = new TypeNodeList();
      Class baseClass = null;
      InterfaceList interfaces = new InterfaceList();
      int i = 0, n = genericParameterConstraints.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParamConstraint) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameterConstraints[k].Param < index)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameterConstraints[i-1].Param == index) i--;
      }
      for (; i < n; i++){
        if (genericParameterConstraints[i].Param == index){
          TypeNode t = this.DecodeAndGetTypeDefOrRefOrSpec(genericParameterConstraints[i].Constraint);
          Class c = t as Class;
          if (c != null)
          {
            if (baseClass == null)
            {
              baseClass = c;
            }
            else
            {
              // CCI1 has a broken view of type parameter constraints. Type parameters are not known to be class constrained or multiple ones can be class constrained.
            }
          }
          else if (t is Interface)
            interfaces.Add((Interface)t);
          constraints.Add(t);
        }else if (sorted)
          break;
      }
      ClassParameter cp = parameter as ClassParameter;
      if (cp == null && baseClass != null) {
        cp = ((ITypeParameter)parameter).DeclaringMember is Method ? new MethodClassParameter() : new ClassParameter();        
        cp.Name = parameter.Name;
        cp.DeclaringMember = ((ITypeParameter)parameter).DeclaringMember;
        cp.ParameterListIndex = ((ITypeParameter)parameter).ParameterListIndex;
        cp.DeclaringModule = this.module;
        cp.TypeParameterFlags = ((ITypeParameter)parameter).TypeParameterFlags;
        cp.ProvideTypeAttributes = this.GetTypeParameterAttributes;
        cp.ProviderHandle = index;
        parameter = cp;
      }
      if (cp != null)
        cp.structuralElementTypes = constraints;
      else
        ((TypeParameter)parameter).structuralElementTypes = constraints;
      if (baseClass != null && cp != null) cp.BaseClass = baseClass;
      parameter.Interfaces = interfaces;
    }
    internal static Block/*!*/ GetOrCreateBlock(TrivialHashtable/*!*/ blockMap, int address) {
      Block block = (Block)blockMap[address+1];
      if (block == null){
        blockMap[address+1] = block = new Block(new StatementList());
#if !FxCop && !CodeContracts
        var sctx = block.SourceContext;
        sctx.StartPos = address;
        block.SourceContext = sctx;
#else
        block.ILOffset = address;
#endif
#if ILOFFSETS
        block.ILOffset = address;
#endif
      }
      return block;
    }
    internal Field GetFieldFromDef(int i){
      return this.GetFieldFromDef(i, null);
    }
    internal Field GetFieldFromDef(int i, TypeNode declaringType){
      FieldRow[] fieldDefs = this.tables.FieldTable;
      FieldRow fld = fieldDefs[i-1];
      if (fld.Field != null) return fld.Field;
      Field field = new Field();
      fieldDefs[i-1].Field = field;
      field.Attributes = this.GetCustomAttributesFor((i << 5)|1);
      field.Flags = (FieldFlags)fld.Flags;
      field.Name = tables.GetIdentifier(fld.Name);
      if ((field.Flags & FieldFlags.RTSpecialName) != 0 && field.Name.UniqueIdKey == StandardIds._Deleted.UniqueIdKey) return null;
      tables.GetSignatureLength(fld.Signature); //sigLength
      MemoryCursor sigReader = this.tables.GetNewCursor();
      GetAndCheckSignatureToken(6, sigReader);
      field.Type = this.ParseTypeSignature(sigReader);
      RequiredModifier reqMod = field.Type as RequiredModifier;
      if (reqMod != null && reqMod.Modifier == CoreSystemTypes.IsVolatile) {
        field.IsVolatile = true;
        field.Type = reqMod.ModifiedType;
      }
      if ((field.Flags & FieldFlags.HasDefault) != 0) 
        field.DefaultValue = this.GetLiteral(i << 2, field.Type);
      if ((field.Flags & FieldFlags.HasFieldMarshal) != 0)
        field.MarshallingInformation = this.GetMarshallingInformation((i << 1)|0);
      if ((field.Flags & FieldFlags.HasFieldRVA) != 0)
        field.InitialData = this.GetInitialData(i, field.Type, out field.section);
      if (declaringType == null){
        TypeDefRow[] typeDefs = this.tables.TypeDefTable;
        int indx = i;
        FieldPtrRow[] fieldPtrs = this.tables.FieldPtrTable;
        int n = fieldPtrs.Length;
        for (int j = 0; j < n; j++){
          if (fieldPtrs[j].Field == i){
            indx = j+1; break;
          }
        }
        n = typeDefs.Length;
        for (int j = n-1; j >= 0; j--){ //TODO: binary search
          TypeDefRow tdr = typeDefs[j];
          if (tdr.FieldList <= indx){
            declaringType = this.GetTypeFromDef(j+1);
            break;
          }
        }
      }
      field.DeclaringType = declaringType;
      if (declaringType != null && (declaringType.Flags & TypeFlags.ExplicitLayout) != 0){
        FieldLayoutRow[] fieldLayouts = this.tables.FieldLayoutTable;
        int n = fieldLayouts.Length;
        for (int j = n-1; j >= 0; j--){ //TODO: binary search
          FieldLayoutRow flr = fieldLayouts[j];
          if (flr.Field == i){
            field.Offset = flr.Offset;
            break;
          }
        }
      }
      return field;
    }
    private byte[] GetInitialData(int fieldIndex, TypeNode fieldType, out PESection targetSection) {
      targetSection = PESection.Text;
      FieldRvaRow[] fieldRvaTable = this.tables.FieldRvaTable;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.FieldRva) % 2 == 1;
      int i = 0, n = fieldRvaTable.Length, j = n-1;
      if (n == 0) return null;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (fieldRvaTable[k].Field < fieldIndex)
            i = k+1;
          else
            j = k;
        }
      }else
        for (; i < j; i++)
          if (fieldRvaTable[i].Field == fieldIndex) break;
      FieldRvaRow frr = fieldRvaTable[i];
      if (frr.Field != fieldIndex) return null;
      Field fld = this.tables.FieldTable[fieldIndex-1].Field;
      if (fld != null) fld.Offset = frr.RVA;
      fieldType = TypeNode.StripModifiers(fieldType);
      EnumNode enumType = fieldType as EnumNode;
      if (enumType != null) fieldType = TypeNode.StripModifiers(enumType.UnderlyingType);
      if (fieldType == null) { Debug.Fail(""); return null; }
      int size = fieldType.ClassSize;
      if (size <= 0){
        switch (fieldType.typeCode){
          case ElementType.Boolean: size = 1; break;
          case ElementType.Char: size = 2; break;
          case ElementType.Double: size = 8; break;
          case ElementType.Int16: size = 2; break;
          case ElementType.Int32: size = 4; break;
          case ElementType.Int64: size = 8; break;
          case ElementType.Int8: size = 1; break;
          case ElementType.Single: size = 4; break;
          case ElementType.UInt16: size = 2; break;
          case ElementType.UInt32: size = 4; break;
          case ElementType.UInt64: size = 8; break;
          case ElementType.UInt8: size = 1; break;
          default:
            if (fieldType is Pointer || fieldType is FunctionPointer){
              size = 4; break;
            }
            //TODO: this seems wrong
            if (i < n-1)
              size = fieldRvaTable[i+1].RVA - frr.RVA;
            else if (targetSection != PESection.Text)
              size = this.tables.GetOffsetToEndOfSection(frr.RVA);
            break;
        }
      }
      if (size <= 0) return null;
      if (this.tables.NoOffsetFor(frr.RVA) || this.tables.NoOffsetFor(frr.RVA+size-1))
        return null;
      MemoryCursor c = this.tables.GetNewCursor(frr.RVA, out targetSection);
      byte[] result = new byte[size];
      for (i = 0; i < size; i++)
        result[i] = c.ReadByte();
      return result;
    }
    private Literal GetLiteral(int parentCodedIndex, TypeNode/*!*/ type) {
      ConstantRow[] constants = this.tables.ConstantTable;
      //TODO: do a binary search
      for (int i = 0, n = constants.Length; i < n; i++){
        if (constants[i].Parent != parentCodedIndex) continue;
        object value = this.tables.GetValueFromBlob(constants[i].Type, constants[i].Value);
        TypeCode valTypeCode = System.Convert.GetTypeCode(value);
        TypeNode underlyingType = type;
        if (type is EnumNode) underlyingType = ((EnumNode)type).UnderlyingType;
        if (underlyingType.TypeCode != valTypeCode) type = CoreSystemTypes.Object;
        if (type == CoreSystemTypes.Object && value != null){
          switch(valTypeCode){
            case TypeCode.Boolean: type = CoreSystemTypes.Boolean; break;
            case TypeCode.Byte: type = CoreSystemTypes.UInt8; break;
            case TypeCode.Char: type = CoreSystemTypes.Char; break;
            case TypeCode.Double: type = CoreSystemTypes.Double; break;
            case TypeCode.Int16: type = CoreSystemTypes.Int16; break;
            case TypeCode.Int32: type = CoreSystemTypes.Int32; break;
            case TypeCode.Int64: type = CoreSystemTypes.Int64; break;
            case TypeCode.SByte: type = CoreSystemTypes.Int8; break;
            case TypeCode.Single: type = CoreSystemTypes.Single; break;
            case TypeCode.String: type = CoreSystemTypes.String; break;
            case TypeCode.UInt16: type = CoreSystemTypes.UInt16; break;
            case TypeCode.UInt32: type = CoreSystemTypes.UInt32; break;
            case TypeCode.UInt64: type = CoreSystemTypes.UInt64; break;
            case TypeCode.Empty:
            case TypeCode.Object: type = CoreSystemTypes.Type; break;
          }
        }
        return new Literal(value, type);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadConstantParentIndex);
    }
    internal FunctionPointer GetCalliSignature(int ssigToken){
#if !FxCop
      StandAloneSigRow ssr = this.tables.StandAloneSigTable[(ssigToken&0xFFFFFF)-1];      
#else
      int index = (ssigToken & 0xFFFFFF) - 1;
      if (index < 0 || index >= this.tables.StandAloneSigTable.Length)
        return null;

      StandAloneSigRow ssr = this.tables.StandAloneSigTable[index];
#endif
      MemoryCursor sigReader = this.tables.GetBlobCursor(ssr.Signature);
      return this.ParseFunctionPointer(sigReader);
    }
    internal void GetLocals(int localIndex, LocalList/*!*/ locals, System.Collections.Generic.Dictionary<int,LocalInfo>/*!*/ localSourceNames) {
      if (localIndex == 0) return;
      StandAloneSigRow ssr = this.tables.StandAloneSigTable[(localIndex & 0xFFFFFF)-1];
      this.tables.GetSignatureLength(ssr.Signature);
      MemoryCursor sigReader = this.tables.GetNewCursor();
      if (sigReader.ReadByte() != 0x7) throw new InvalidMetadataException(ExceptionStrings.InvalidLocalSignature);
      int count = sigReader.ReadCompressedInt();
      for (int i = 0; i < count; i++){
        LocalInfo localInfo;
        var hasPDBInfo = localSourceNames.TryGetValue(i, out localInfo);
        string lookupName = localInfo.Name;
        bool hasNoPDBName = String.IsNullOrEmpty(lookupName);
#if !FxCop
        string name = hasNoPDBName ? "local"+i : lookupName;
#else
        string name = hasNoPDBName ? "local$"+i : lookupName;
#endif
        bool pinned = false;
        TypeNode locType = this.ParseTypeSignature(sigReader, ref pinned);
        Local loc = new Local(Identifier.For(name), locType);
        loc.Pinned = pinned;
        loc.HasNoPDBInfo = !hasPDBInfo;
        loc.Attributes = localInfo.Attributes;
        locals.Add(loc);
      }
    }
#if !ROTOR
    internal void GetLocalSourceNames(ISymUnmanagedScope/*!*/ scope, System.Collections.Generic.Dictionary<int,LocalInfo>/*!*/ localSourceNames) {
      uint numLocals = scope.GetLocalCount();
      IntPtr[] localPtrs = new IntPtr[numLocals];
      scope.GetLocals((uint)localPtrs.Length, out numLocals, localPtrs);

      char[] nameBuffer = new char[100];
      uint nameLen;
      for (int i=0; i<numLocals; i++){
        ISymUnmanagedVariable local =
          (ISymUnmanagedVariable)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(localPtrs[i], typeof(ISymUnmanagedVariable));
        if (local != null){
          local.GetName((uint)0, out nameLen, null);
          if (nameLen > nameBuffer.Length)
          {
            nameBuffer = new char[nameLen];
          }
          local.GetName((uint)nameBuffer.Length, out nameLen, nameBuffer);
          int localIndex = (int)local.GetAddressField1();
          var localName = new String(nameBuffer, 0, (int)nameLen-1);
          uint attributes = local.GetAttributes();
          localSourceNames[localIndex] = new LocalInfo(localName, attributes);
          System.Runtime.InteropServices.Marshal.ReleaseComObject(local);
        }
        System.Runtime.InteropServices.Marshal.Release(localPtrs[i]);
      }

      IntPtr[] subscopes = new IntPtr[100];
      uint numScopes;
      scope.GetChildren((uint)subscopes.Length, out numScopes, subscopes);
      for (int i=0; i<numScopes; i++){
        ISymUnmanagedScope subscope = 
          (ISymUnmanagedScope)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(subscopes[i], typeof(ISymUnmanagedScope));
        if (subscope != null){
          this.GetLocalSourceNames(subscope, localSourceNames);
          System.Runtime.InteropServices.Marshal.ReleaseComObject(subscope);
        }
        System.Runtime.InteropServices.Marshal.Release(subscopes[i]);
        //TODO: need to figure out how map these scope to blocks and set HasLocals on those blocks
      }
    }
#endif
    private MarshallingInformation GetMarshallingInformation(int parentCodedIndex){
      FieldMarshalRow[] mtypes = this.tables.FieldMarshalTable;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.FieldMarshal) % 2 == 1;
      int i = 0, n = mtypes.Length, j = n-1;
      if (n == 0) return null;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (mtypes[k].Parent < parentCodedIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && mtypes[i-1].Parent == parentCodedIndex) i--;
      }else
        for (; i < j; i++)
          if (mtypes[i].Parent == parentCodedIndex) break;
      FieldMarshalRow fmr = mtypes[i];
      if (fmr.Parent != parentCodedIndex) return null;
      MarshallingInformation result = new MarshallingInformation();
      int blobSize = 0;
      MemoryCursor c = this.tables.GetBlobCursor(fmr.NativeType, out blobSize);
      int initialPosition = c.Position;
      result.NativeType = (NativeType)c.ReadByte();
      if (result.NativeType == NativeType.CustomMarshaler){
        c.ReadUInt16(); //Skip over 0
        result.Class = ReadSerString(c);
        result.Cookie = ReadSerString(c);
      }else if (blobSize > 1){
        if (result.NativeType == NativeType.LPArray){
          result.ElementType = (NativeType)c.ReadByte();
          result.ParamIndex = -1;
          int bytesRead = 2;
          if (bytesRead < blobSize){
            int pos = c.Position;
            result.ParamIndex = c.ReadCompressedInt();
            bytesRead += c.Position - pos;
            if (bytesRead < blobSize){
              pos = c.Position;
              result.ElementSize = c.ReadCompressedInt();
              bytesRead += c.Position - pos;
              if (bytesRead < blobSize)
                result.NumberOfElements = c.ReadCompressedInt();
            }
          }
        }else if (result.NativeType == NativeType.SafeArray){
          result.ElementType = (NativeType)c.ReadByte(); //Actually a variant type. TODO: what about VT_VECTOR VT_ARRAY and VT_BYREF?
          if (c.Position < initialPosition+blobSize-1)
            result.Class = ReadSerString(c);
        } else {
          result.Size = c.ReadCompressedInt();
          if (result.NativeType == NativeType.ByValArray) {
            if (c.Position < initialPosition + blobSize) 
              result.ElementType = (NativeType)c.ReadByte();
            else
              result.ElementType = NativeType.NotSpecified;
          }
        }
      }
      return result;
    }
    private void GetMethodBody(Method/*!*/ method, object/*!*/ i, bool asInstructionList) {
      if (asInstructionList){this.GetMethodInstructions(method, i); return;}
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      this.currentMethodTypeParameters = method.templateParameters;
      TypeNode savedCurrentType = this.currentType;
      this.currentType = method.DeclaringType;
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      this.currentTypeParameters = this.currentType.TemplateParameters;
      try{
        MethodRow meth = this.tables.MethodTable[((int)i)-1];
        StatementList statements;
        if (meth.RVA != 0 && (((MethodImplFlags)meth.ImplFlags) & MethodImplFlags.ManagedMask) == MethodImplFlags.Managed){
          if (this.getDebugSymbols) this.GetMethodDebugSymbols(method, 0x6000000|(uint)(int)i);
          statements = this.ParseMethodBody(method, (int)i, meth.RVA);
        }else
          statements = new StatementList(0);
        method.Body = new Block(statements);
#if FxCop
        if (statements.Count > 0) {
          SourceContext context = statements[0].SourceContext;
          method.SourceContext = context;
          method.Body.SourceContext = context;
        }
#endif
#if !MinimalReader
        method.Body.HasLocals = true;
#endif
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        method.Body = new Block(new StatementList(0));
#endif
      }finally{
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
        this.currentType = savedCurrentType;
        this.currentTypeParameters = savedCurrentTypeParameters;
      }
    }
    private void GetMethodDebugSymbols(Method/*!*/ method, uint methodToken)
      //^ requires this.debugReader != null;
    {
#if !ROTOR
      ISymUnmanagedMethod methodInfo = null;
      try{
        try{
          this.debugReader.GetMethod(methodToken, ref methodInfo);
          this.debugDocuments = new Collections.Generic.Dictionary<IntPtr,UnmanagedDocument>(2); // typically methods have 1 doc
          method.RecordSequencePoints(methodInfo, this.debugDocuments);
        }catch (COMException){
        }catch (InvalidCastException){
        }catch (System.Runtime.InteropServices.InvalidComObjectException){}
      }finally{
        if (methodInfo != null)
          Marshal.ReleaseComObject(methodInfo);
      }
#endif
    }
    private void GetMethodInstructions(Method/*!*/ method, object/*!*/ i) {
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      this.currentMethodTypeParameters = method.templateParameters;
      TypeNode savedCurrentType = this.currentType;
      this.currentType = method.DeclaringType;
      try{
        MethodRow meth = this.tables.MethodTable[((int)i)-1];
        if (meth.RVA != 0 && (((MethodImplFlags)meth.ImplFlags) & MethodImplFlags.ManagedMask) == MethodImplFlags.Managed){
          if (this.getDebugSymbols) this.GetMethodDebugSymbols(method, 0x6000000|(uint)(int)i);
          method.Instructions = this.ParseMethodInstructions(method, (int)i, meth.RVA);
        }else
          method.Instructions = new InstructionList(0);
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        method.Instructions = new InstructionList(0);
#endif
      }finally{
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
        this.currentType = savedCurrentType;
      }
    }
    internal Method GetMethodDefOrRef(int codedIndex){
      switch(codedIndex & 0x1){
        case 0x00 : return this.GetMethodFromDef(codedIndex >> 1); 
        case 0x01 :
          TypeNodeList varArgTypes;
          return (Method)this.GetMemberFromRef(codedIndex >> 1, out varArgTypes);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
    }
    private Method GetMethodDefOrRef(int codedIndex, int numberOfGenericArguments) {
      switch(codedIndex & 0x1){
        case 0x00 : return this.GetMethodFromDef(codedIndex >> 1); 
        case 0x01 :
          TypeNodeList varArgTypes;
          return (Method)this.GetMemberFromRef(codedIndex >> 1, out varArgTypes, numberOfGenericArguments);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
    }
    internal Method/*!*/ GetMethodFromDef(int index) {
      return this.GetMethodFromDef(index, null);
    }
    internal Method/*!*/ GetMethodFromDef(int index, TypeNode declaringType) {
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      MethodRow[] methodDefs = this.tables.MethodTable;
      MethodRow meth = methodDefs[index-1];
      if (meth.Method != null) return meth.Method;
      if (declaringType == null){
        int indx = index;
        MethodPtrRow[] methodPtrs = this.tables.MethodPtrTable;
        int n = methodPtrs.Length, i = 0, j = n-1;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodPtr) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (methodPtrs[k].Method < index)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && methodPtrs[i-1].Method == index) i--;
        }
        for (; i < n; i++){
          if (methodPtrs[i].Method == index){
            indx = i+1; break;
          }
        }
        TypeDefRow[] typeDefs = this.tables.TypeDefTable;
        n = typeDefs.Length; i=0; j=n-1;
        sorted = (this.sortedTablesMask >> (int)TableIndices.TypeDef) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (typeDefs[k].MethodList < indx)
              i = k+1;
            else
              j = k;
          }
          j = i;
          while (j < n-1 && typeDefs[j+1].MethodList == indx) j++;
        }
        for (; j >= 0; j--){
          if (typeDefs[j].MethodList <= indx){
            declaringType = this.GetTypeFromDef(j+1);
            break;
          }
        }
      }
      Method.MethodBodyProvider provider = new Method.MethodBodyProvider(this.GetMethodBody);
      Identifier name = tables.GetIdentifier(meth.Name);
      Method method;
      if ((((MethodFlags)meth.Flags) & MethodFlags.SpecialName) != 0 &&
        (((MethodFlags)meth.Flags) & MethodFlags.SpecialName) != 0)
      {
        if (name.Name == ".ctor")
        {
#if ILOFFSETS
          method = methodDefs[index - 1].Method = new InstanceInitializer(provider, index, (int)TableIndices.Method << 24 | index);
#else
          method = methodDefs[index - 1].Method = new InstanceInitializer(provider, index);
#endif
        }
        else if (name.Name == ".cctor")
        {
#if ILOFFSETS
          method = methodDefs[index - 1].Method = new StaticInitializer(provider, index, (int)TableIndices.Method << 24 | index);
#else
          method = methodDefs[index - 1].Method = new StaticInitializer(provider, index);
#endif
        }
        else
        {
#if ILOFFSETS
          method = methodDefs[index - 1].Method = new Method(provider, index, (int)TableIndices.Method << 24 | index);
#else
          method = methodDefs[index - 1].Method = new Method(provider, index);
#endif
        }
      }
      else
      {
#if ILOFFSETS
        method = methodDefs[index - 1].Method = new Method(provider, index, (int)TableIndices.Method << 24 | index);
#else
        method = methodDefs[index - 1].Method = new Method(provider, index);
#endif
      }
      method.ProvideMethodAttributes = new Method.MethodAttributeProvider(this.GetMethodAttributes);
      //method.Attributes = this.GetCustomAttributesFor((index << 5)|0); //TODO: get attributes lazily
      method.Flags = (MethodFlags)meth.Flags;
      method.ImplFlags = (MethodImplFlags)meth.ImplFlags;
      method.Name = name;
      if (declaringType != null) {
        if (declaringType.IsGeneric) {
          if (declaringType.Template != null)
            this.currentTypeParameters = declaringType.ConsolidatedTemplateArguments;
          else
            this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters;
        }
        if (this.module.ProjectTypesContainedInModule && (declaringType.Flags & TypeFlags.IsForeign) != 0) {
          if (method.IsStatic) method.Flags &= ~MethodFlags.NewSlot;
          if (declaringType is DelegateNode) {
            method.Flags &= ~MethodFlags.MethodAccessMask;
            method.Flags |= MethodFlags.Public;
          } else {
            method.ImplFlags |= MethodImplFlags.Runtime | MethodImplFlags.InternalCall;
          }
        }
      }
      
      tables.GetSignatureLength(meth.Signature);
      MemoryCursor sigReader = this.tables.GetNewCursor();
      method.CallingConvention = (CallingConventionFlags)sigReader.ReadByte();
      if (method.IsGeneric = (method.CallingConvention & CallingConventionFlags.Generic) != 0){
        int numTemplateParameters = sigReader.ReadCompressedInt();
        this.currentMethodTypeParameters = new TypeNodeList(numTemplateParameters);
        this.currentMethodTypeParameters = method.TemplateParameters = this.GetTypeParametersFor((index << 1)|1, method);
        this.GetTypeParameterConstraints((index << 1)|1, method.TemplateParameters);
      }
      int numParams = sigReader.ReadCompressedInt();
      method.ReturnType = this.ParseTypeSignature(sigReader);
#if false
      if (declaringType != null && declaringType.IsValueType)
        method.ThisParameter = new This(declaringType.GetReferenceType());
      else
        method.ThisParameter = new This(declaringType);
#endif // materialized on demand
      ParameterList paramList = method.Parameters = new ParameterList(numParams);
      if (numParams > 0){
        int offset = method.IsStatic ? 0 : 1;
        for (int i = 0; i < numParams; i++){
          Parameter param = new Parameter();
          param.ParameterListIndex = i;
          param.ArgumentListIndex = i+offset;
          param.Type = this.ParseTypeSignature(sigReader);
          param.DeclaringMethod = method;
          paramList.Add(param);
        }
        int end = this.tables.ParamTable.Length+1;
        if (index < methodDefs.Length) end = methodDefs[index].ParamList;
        this.AddMoreStuffToParameters(method, paramList, meth.ParamList, end);
        for (int i = 0; i < numParams; i++){
          Parameter param = paramList[i];
          if (param.Name == null) {
            param.Name = Identifier.For("param" + (i));
            param.Flags |= ParameterFlags.ParameterNameMissing;
          }

        }
      }else if (method.ReturnType != CoreSystemTypes.Void){
        //check for custom attributes and marshalling information on return value
        int i = meth.ParamList;
        ParamPtrRow[] parPtrs = this.tables.ParamPtrTable; //TODO: why use ParamPtrTable in the branch and not the one above? Factor this out.
        ParamRow[] pars = this.tables.ParamTable;
        int n = methodDefs.Length;
        int m = pars.Length;
        if (index < n) m = methodDefs[index].ParamList-1;
        if (parPtrs.Length > 0){
          if (pars != null && 0 < i && i <= m){
            int j = parPtrs[i-1].Param;
            ParamRow pr = pars[j-1];
            if (pr.Sequence == 0)
              this.AddMoreStuffToParameters(method, null, j, j+1);
          }
        }else{
          if (pars != null && 0 < i && i <= m){
            ParamRow pr = pars[i-1];
            if (pr.Sequence == 0)
              this.AddMoreStuffToParameters(method, null, i, i+1);
          }
        }
      }
#if ExtendedRuntime
      for (int k = 0, al = method.ReturnAttributes == null ? 0 : method.ReturnAttributes.Count; k < al; k++) {
        if (method.ReturnAttributes[k].Type == ExtendedRuntimeTypes.NotNullAttribute) {
          method.ReturnType = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, method.ReturnType);
          // Someone putting an attribute directly on the "real" method is still a
          // kind of out-of-band contract.
          // This marking is the way to signal that any override or implementing method being compiled
          // should not have its non-null annotations persisted as optional modifiers.
          method.HasOutOfBandContract = true;
        } else  if (method.ReturnAttributes[k].Type == ExtendedRuntimeTypes.NotNullArrayElementsAttribute) {
          Stack s = new Stack();
          TypeNode t = method.ReturnType;
          while (t is OptionalModifier) {
            OptionalModifier om = t as OptionalModifier;
            s.Push(om.Modifier);
            t = om.ModifiedType;
          }
          ArrayType at = t as ArrayType;
          if (at != null) { // just silently ignore if attribute is on a non-array type?
            OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, at.ElementType);
            while (0 < s.Count) {
              om = OptionalModifier.For((TypeNode)s.Pop(), om);
            }
            // also *must* make it a new array type, can't set the ElementType.
            method.ReturnType = om.GetArrayType(1);
            // Someone putting an attribute directly on the "real" method is still a
            // kind of out-of-band contract.
            // This marking is the way to signal that any override or implementing method being compiled
            // should not have its non-null annotations persisted as optional modifiers.
            method.HasOutOfBandContract = true;
          }
        }
      }
#endif
      //if ((method.Flags & MethodFlags.HasSecurity) != 0)
      //  method.SecurityAttributes = this.GetSecurityAttributesFor((index << 2)|1);
      if ((method.Flags & MethodFlags.PInvokeImpl) != 0){
        ImplMapRow[] implMaps = this.tables.ImplMapTable;
        int n = implMaps.Length, i = 0, j = n-1;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.ImplMap) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if ((implMaps[k].MemberForwarded >> 1) < index)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && (implMaps[i-1].MemberForwarded>>1) == index) i--;
        }
        for (; i < n; i++){          
          ImplMapRow imr = implMaps[i];
          if (imr.MemberForwarded >> 1 == index){
            method.PInvokeFlags = (PInvokeFlags)imr.MappingFlags;
            method.PInvokeImportName = tables.GetString(imr.ImportName);
            method.PInvokeModule = this.module.ModuleReferences[imr.ImportScope-1].Module;
            break;
          }
        }
      }
      method.DeclaringType = declaringType;
      this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
      this.currentTypeParameters = savedCurrentTypeParameters;
      return method;
    }
    private void GetMethodAttributes(Method/*!*/ method, object/*!*/ handle) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      try {
        MetadataReader tables = this.tables;
        int index = (int)handle;
        MethodRow[] methodDefs = tables.MethodTable;
        int n = methodDefs.Length;
        if (index < 1 || index > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        MethodRow md = methodDefs[index-1];
        if (method != md.Method) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        //Get custom attributes   
        method.Attributes = this.GetCustomAttributesNonNullFor((index << 5)|0);
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
        //Get security attributes
        if ((method.Flags & MethodFlags.HasSecurity) != 0)
          method.SecurityAttributes = this.GetSecurityAttributesFor((index << 2)|1);
#if !FxCop
      } catch (Exception e) {
        if (this.module != null) {
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        method.Attributes = new AttributeList(0);
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
      }
#else
      }finally{}
#endif
    }
    private Method/*!*/ GetMethodFromSpec(int i) {
      MethodSpecRow[] methodSpecs = this.tables.MethodSpecTable;
      MethodSpecRow msr = methodSpecs[i-1];
      if (msr.InstantiatedMethod != null) return msr.InstantiatedMethod;
      MemoryCursor sigReader = this.tables.GetBlobCursor(msr.Instantiation);
      byte header = sigReader.ReadByte(); //skip over redundant header byte
      Debug.Assert(header == 0x0a);
      TypeNodeList templateArguments = this.ParseTypeList(sigReader);
      Method template = this.GetMethodDefOrRef(msr.Method, templateArguments.Count);
      if (template == null) return new Method();
      if (template.TemplateParameters == null) return template; //Likely a dummy method
      return template.GetTemplateInstance(this.currentType, templateArguments);
    }
    internal Member/*!*/ GetMemberFromToken(int tok, object memberInfo = null) {
      TypeNodeList varArgTypes;
      return this.GetMemberFromToken(tok, out varArgTypes, memberInfo);
    }
    internal Member/*!*/ GetMemberFromToken(int tok, out TypeNodeList varArgTypes, object memberInfo = null) {
      varArgTypes = null;
      Member member = null;
      switch ((TableIndices)(tok >> 24)){
        case TableIndices.Field : member = this.GetFieldFromDef(tok & 0xFFFFFF); break;
        case TableIndices.Method : member = this.GetMethodFromDef(tok & 0xFFFFFF); break;
        case TableIndices.MemberRef : member = this.GetMemberFromRef(tok & 0xFFFFFF, out varArgTypes, memberInfo); break;
        case TableIndices.TypeDef : member = this.GetTypeFromDef(tok & 0xFFFFFF); break;
        case TableIndices.TypeRef : member = this.GetTypeFromRef(tok & 0xFFFFFF); break;
        case TableIndices.TypeSpec : member = this.GetTypeFromSpec(tok & 0xFFFFFF); break;
        case TableIndices.MethodSpec : member = this.GetMethodFromSpec(tok & 0xFFFFFF); break;
        default: throw new InvalidMetadataException(ExceptionStrings.BadMemberToken);
      }
      if (member == null) throw new InvalidMetadataException(ExceptionStrings.BadMemberToken);
      return member;
    }
    internal Member GetMemberFromRef(int i, out TypeNodeList varArgTypes, object memberInfo = null) {
      return this.GetMemberFromRef(i, out varArgTypes, 0, memberInfo);
    }
    internal Member GetMemberFromRef(int i, out TypeNodeList varArgTypes, int numGenericArgs, object memberInfo = null) {
      MemberRefRow mref = this.tables.MemberRefTable[i-1];
      if (mref.Member != null){
        varArgTypes = mref.VarargTypes;
        return mref.Member;
      }
      varArgTypes = null;
      Member result = null;
      int codedIndex = mref.Class;
      if (codedIndex == 0) return null;
      TypeNode parent = null;
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      switch(codedIndex & 0x7){
        case 0x00 : parent = this.GetTypeFromDef(codedIndex >> 3); break;
        case 0x01 : parent = this.GetTypeFromRef(codedIndex >> 3); break;
        case 0x02 : parent = this.GetTypeGlobalMemberContainerTypeFromModule(codedIndex >> 3); break;
        case 0x03 : result = this.GetMethodFromDef(codedIndex >> 3); 
          if ((((Method)result).CallingConvention & CallingConventionFlags.VarArg) != 0){
            MemoryCursor sRdr = this.tables.GetBlobCursor(mref.Signature);
            sRdr.ReadByte(); //hdr
            int pCount = sRdr.ReadCompressedInt();
            this.ParseTypeSignature(sRdr); //rType
            bool genParameterEncountered = false;
            this.ParseParameterTypes(out varArgTypes, sRdr, pCount, ref genParameterEncountered);
          }
          goto done;
        case 0x04 : parent = this.GetTypeFromSpec(codedIndex >> 3); break;
        default: throw new InvalidMetadataException("");
      }
      if (parent != null && parent.IsGeneric){
        if (parent.Template != null)
          this.currentTypeParameters = parent.ConsolidatedTemplateArguments;
        else
          this.currentTypeParameters = parent.ConsolidatedTemplateParameters;
      }
      Identifier memberName = this.tables.GetIdentifier(mref.Name);
      Method methodToSkipPastWhenLookingForMethodParameters = null;
    tryAgain:
      MemoryCursor sigReader = this.tables.GetBlobCursor(mref.Signature);
      byte header = sigReader.ReadByte();
      if (header == 0x6){
        TypeNode fieldType = this.ParseTypeSignature(sigReader);
        TypeNode fType = TypeNode.StripModifiers(fieldType);
        TypeNode parnt = parent;
        while (parnt != null){
          MemberList members = parnt.Members;
          for (int j = 0, n = members.Count; j < n; j++){
            Field f = members[j] as Field;
            if (f == null) continue;
            if (f.Name.UniqueIdKey != memberName.UniqueIdKey) continue;
            if (TypeNode.StripModifiers(f.Type) == fType){result = f; goto done;}
          }
          Class c = parnt as Class;
          if (c != null) parnt = c.BaseClass; else break;
        }
        if (result == null){
          result = new Field(memberName);
          result.DeclaringType = parent;
          ((Field)result).Type = fieldType;
          var fieldInfo = memberInfo as FieldInfo;
          if (fieldInfo != null && fieldInfo.IsStatic)
          {
            ((Field)result).Flags |= FieldFlags.Static;
          }
          goto error;
        }
        goto done;
      }
      int typeParamCount = int.MinValue;
      CallingConventionFlags callingConvention = CallingConventionFlags.Default;
      if ((header & 0x20) != 0) callingConvention |= CallingConventionFlags.HasThis;
      if ((header & 0x40) != 0) callingConvention |= CallingConventionFlags.ExplicitThis;
      switch (header & 7){
        case 1: callingConvention |= CallingConventionFlags.C; break;
        case 2: callingConvention |= CallingConventionFlags.StandardCall; break;
        case 3: callingConvention |= CallingConventionFlags.ThisCall; break;
        case 4: callingConvention |= CallingConventionFlags.FastCall; break;
        case 5: callingConvention |= CallingConventionFlags.VarArg; break;
      }
      if ((header & 0x10) != 0){
        typeParamCount = sigReader.ReadCompressedInt();
        callingConvention |= CallingConventionFlags.Generic;
      }
      int paramCount = sigReader.ReadCompressedInt();
      TypeNodeList savedMethodTypeParameters = this.currentMethodTypeParameters;
      TypeNode pnt = parent;
      if (numGenericArgs > 0){
        bool skip = methodToSkipPastWhenLookingForMethodParameters != null;
        while (pnt != null){
          MemberList members = pnt.GetMembersNamed(memberName);        
          for (int k = 0, n = members.Count; k < n; k++){
            Method m = members[k] as Method;
            if (m == null) continue;
            if (skip) {
              if (m == methodToSkipPastWhenLookingForMethodParameters) skip = false;
              continue;
            }
            if (m.TemplateParameters == null || m.TemplateParameters.Count != numGenericArgs) continue;
            if (m.Parameters == null || m.Parameters.Count != paramCount) continue;
            this.currentMethodTypeParameters = m.TemplateParameters;
            this.currentTypeParameters = pnt.ConsolidatedTemplateArguments;
            methodToSkipPastWhenLookingForMethodParameters = m;
            goto parseSignature;
          }
          Class c = pnt as Class;
          if (c != null) pnt = c.BaseClass; else break;
        }
        methodToSkipPastWhenLookingForMethodParameters = null;
      }
    parseSignature:
      TypeNode returnType = this.ParseTypeSignature(sigReader);
      if (returnType == null) returnType = CoreSystemTypes.Object;
      bool genericParameterEncountered = returnType.IsGeneric;
      TypeNodeList paramTypes = this.ParseParameterTypes(out varArgTypes, sigReader, paramCount, ref genericParameterEncountered);
      this.currentMethodTypeParameters = savedMethodTypeParameters;
      this.currentTypeParameters = savedCurrentTypeParameters;
      pnt = parent;
      while (pnt != null){
        MemberList members = pnt.GetMembersNamed(memberName);        
        for (int k = 0, n = members.Count; k < n; k++){
          Method m = members[k] as Method;
          if (m == null) continue;
          if (m.ReturnType == null) continue;
          TypeNode mrtype = TypeNode.StripModifiers(m.ReturnType);
          //^ assert mrtype != null;
          if (!mrtype.IsStructurallyEquivalentTo(TypeNode.StripModifiers(returnType))) continue;
          if (!m.ParameterTypesMatchStructurally(paramTypes)) continue;
          if (m.CallingConvention != callingConvention) continue;
          if (typeParamCount != int.MinValue && (!m.IsGeneric || m.TemplateParameters == null || m.TemplateParameters.Count != typeParamCount))
            continue;
          result = m;
          goto done;
        }
        if (memberName.UniqueIdKey == StandardIds.Ctor.UniqueIdKey){
          //Can't run up the base class chain for constructors.
          members = pnt.GetConstructors();
          if (members != null && members.Count == 1 && paramCount == 0){
            //Only one constructor. The CLR metadata API's seem to think that this should match the empty signature
            result = members[0];
            goto done;
          }
          break;
        }
        Class c = pnt as Class;
        if (c != null)
          pnt = c.BaseClass;
        else {
          Interface iface = pnt as Interface;
          if (iface != null) {
            for (int k = 0, n = iface == null ? 0 : iface.Interfaces.Count; k < n; k++) {
              result = this.SearchBaseInterface(iface.Interfaces[k], memberName, returnType, paramTypes, typeParamCount, callingConvention);
              if (result != null) goto done;
            }
          }
          break;
        }
      }
      if (result == null){
        if (methodToSkipPastWhenLookingForMethodParameters != null) goto tryAgain;
        ParameterList parameters = new ParameterList(paramCount);
        for (int j = 0; j < paramCount; j++){
          Parameter p = new Parameter(Identifier.Empty, paramTypes[j]);
          parameters.Add(p);
        }
        //TODO: let the caller indicate if it expects a constructor
        Method meth = new Method(parent, null, memberName, parameters, returnType, null);
        meth.CallingConvention = callingConvention;
        if ((callingConvention & CallingConventionFlags.HasThis) == 0) meth.Flags |= MethodFlags.Static;
        result = meth;
      }
    error:
      if (this.module != null){
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture,
          ExceptionStrings.CouldNotResolveMemberReference, parent.FullName + "::" + memberName));
        if (parent != null) parent.Members.Add(result);
      }
    done:
      if (Reader.CanCacheMember(result)) {
        this.tables.MemberRefTable[i - 1].Member = result;
        this.tables.MemberRefTable[i - 1].VarargTypes = varArgTypes;
      }
      this.currentTypeParameters = savedCurrentTypeParameters;
      return result;
    }
    private Method SearchBaseInterface(Interface iface, Identifier memberName, TypeNode returnType, TypeNodeList paramTypes, int typeParamCount, CallingConventionFlags callingConvention) {
      MemberList members = iface.GetMembersNamed(memberName);
      for (int k = 0, n = members.Count; k < n; k++) {
        Method m = members[k] as Method;
        if (m == null) continue;
        if (m.ReturnType == null) continue;
        TypeNode mrtype = TypeNode.StripModifiers(m.ReturnType);
        //^ assert mrtype != null;
        if (!mrtype.IsStructurallyEquivalentTo(TypeNode.StripModifiers(returnType))) continue;
        if (!m.ParameterTypesMatchStructurally(paramTypes)) continue;
        if (m.CallingConvention != callingConvention) continue;
        if (typeParamCount != int.MinValue && (!m.IsGeneric || m.TemplateParameters == null || m.TemplateParameters.Count != typeParamCount))
          continue;
        return m;
      }
      for (int k = 0, n = iface == null ? 0 : iface.Interfaces.Count; k < n; k++) {
        var m = this.SearchBaseInterface(iface.Interfaces[k], memberName, returnType, paramTypes, typeParamCount, callingConvention);
        if (m != null) return m;
      }
      return null;
    }
    private static bool CanCacheMethodHelper(Method/*!*/ method){
      if (method.IsGeneric) {
        if (method.TemplateArguments == null)
          return false;
        for (int i = 0; i < method.TemplateArguments.Count; i++)
          if (!CanCacheTypeNode(method.TemplateArguments[i]))
            return false;
      }
      return true;
    }
    private static bool CanCacheMember(Member/*!*/ member){
      return (member.DeclaringType == null || CanCacheTypeNode(member.DeclaringType)) &&
        (member.NodeType != NodeType.Method || CanCacheMethodHelper((Method)member));
    }

    private TypeNodeList/*!*/ ParseParameterTypes(out TypeNodeList varArgTypes, MemoryCursor/*!*/ sigReader, int paramCount, ref bool genericParameterEncountered) {
      varArgTypes = null;
      TypeNodeList paramTypes = new TypeNodeList(paramCount);
      for (int j = 0; j < paramCount; j++) {
        TypeNode paramType = this.ParseTypeSignature(sigReader);
        if (paramType == null) {
          //got a sentinel
          varArgTypes = new TypeNodeList(paramCount - j);
          j--;
          continue;
        }
        if (varArgTypes != null) { varArgTypes.Add(paramType); continue; }
        if (paramType.IsGeneric) genericParameterEncountered = true;
        paramTypes.Add(paramType);
      }
      return paramTypes;
    }
    private bool TypeDefIsClass(int i){
      if (i == 0) return false;
      TypeDefRow typeDef = this.tables.TypeDefTable[i-1];
      if (typeDef.Type != null) return typeDef.Type is Class;
      if ((typeDef.Flags & (int)TypeFlags.Interface) != 0) return false;
      return this.TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(typeDef.Extends);
    }
    private bool TypeDefIsClassButNotValueTypeBaseClass(int i){
      if (i == 0) return false;
      TypeDefRow typeDef = this.tables.TypeDefTable[i - 1];
      if (typeDef.Type != null) return typeDef.Type != CoreSystemTypes.ValueType && typeDef.Type != CoreSystemTypes.Enum && typeDef.Type is Class;
      if ((typeDef.Flags & (int)TypeFlags.Interface) != 0) return false;
      return this.TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(typeDef.Extends);
    }
    internal TypeNodeList GetInstantiatedTypes() {
      TypeNodeList result = null;
      TypeDefRow[] typeDefs = this.tables.TypeDefTable;
      for (int i = 0, n = typeDefs.Length; i < n; i++){
        TypeNode t = typeDefs[i].Type;
        if (t == null) continue;
        if (result == null) result = new TypeNodeList();
        result.Add(t);
      }
      return result;
    }
    internal TypeNode/*!*/ GetTypeFromDef(int i) {
      TypeDefRow typeDef = this.tables.TypeDefTable[i-1];
      if (typeDef.Type != null) return typeDef.Type;
      // Save current state because the helper might change it but this method must not.
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNode savedCurrentType = this.currentType;
      try{
        return this.GetTypeFromDefHelper(i);
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return new Class();
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return new Class();
#endif
      }finally{
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentType = savedCurrentType;
      }
    }
    internal TypeNode/*!*/ GetTypeFromDefHelper(int i) {
      // This is added to prevent loops. 
      //  Check the code in GetTypeFromDef which checks != null before callig this function
      this.tables.TypeDefTable[i - 1].Type = Class.Dummy;
      TypeDefRow typeDef = this.tables.TypeDefTable[i - 1];
      Identifier name = this.tables.GetIdentifier(typeDef.Name);
      Identifier namesp = this.tables.GetIdentifier(typeDef.Namespace);
      if (namesp.Name.Length > 0 && (((TypeFlags)typeDef.Flags) & TypeFlags.VisibilityMask) >= TypeFlags.NestedPublic) {
        name = Identifier.For(namesp.Name + "." + name.Name);
        namesp = Identifier.Empty;
      }
      TypeNode result = this.GetReplacedTypeFromName(namesp, name);
      if (result != null) {
        this.tables.TypeDefTable[i-1].Type = result;
        this.currentType = result;
        return result;
      }
      int firstInterfaceIndex;
      int lastInterfaceIndex;
      this.GetInterfaceIndices(i, out firstInterfaceIndex, out lastInterfaceIndex);
      InterfaceList interfaces = new InterfaceList();
      result = this.ConstructCorrectTypeNodeSubclass(i, namesp, firstInterfaceIndex, lastInterfaceIndex, 
        (TypeFlags)typeDef.Flags, interfaces, typeDef.Extends, 
        name.UniqueIdKey == StandardIds.Enum.UniqueIdKey && namesp.UniqueIdKey == StandardIds.System.UniqueIdKey);
      result.DeclaringModule = this.module;
      result.Name = name;
      result.Namespace = namesp;
      TypeNodeList typeParameters = this.currentTypeParameters = this.GetTypeParametersFor((i << 1)|0, result);
      result.TemplateParameters = typeParameters;
      result.IsGeneric = typeParameters != null;
      this.tables.TypeDefTable[i-1].Type = result;
      this.currentType = result;
      this.RemoveTypeParametersBelongingToDeclaringType(i, ref typeParameters, result);
      //Now that the type instance has been allocated, it is safe to get hold of things that could refer to this type.
      if (result is Class && result.BaseType == null){
        TypeNode baseType = this.DecodeAndGetTypeDefOrRefOrSpec(typeDef.Extends);
        ((Class)result).BaseClass = baseType as Class;
        if (baseType != null && !(baseType is Class) && this.module != null){
          HandleError(this.module, ExceptionStrings.InvalidBaseClass);
        }
      }
      if (result.IsGeneric) {
        this.GetTypeParameterConstraints((i << 1)|0, typeParameters);
        if (result.templateParameters != null) {
          for (int j = 0, offset = typeParameters.Count-result.templateParameters.Count, n = result.templateParameters.Count; j < n; j++)
            result.templateParameters[j] = typeParameters[j+offset];
        }
      }
      if (firstInterfaceIndex >= 0)
        this.GetInterfaces(i, firstInterfaceIndex, interfaces);
      if ((result.Flags & (TypeFlags.ExplicitLayout|TypeFlags.SequentialLayout)) != 0)
        this.GetClassSizeAndPackingSize(i, result);
      return result;
    }

    private void GetInterfaceIndices(int i, out int firstInterfaceIndex, out int lastInterfaceIndex) {
      firstInterfaceIndex = -1;
      lastInterfaceIndex = -1;
      InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable;
      //TODO: binary search
      for (int j = 0, n = intfaces.Length; j < n; j++) {
        if (intfaces[j].Class != i) continue;
        if (firstInterfaceIndex == -1)
          firstInterfaceIndex = j;
        lastInterfaceIndex = j;
      }
    }

    private void GetClassSizeAndPackingSize(int i, TypeNode/*!*/ result) {
      ClassLayoutRow[] classLayouts = tables.ClassLayoutTable;
      for (int j = 0, n = classLayouts.Length; j < n; j++) { //TODO: binary search
        ClassLayoutRow clr = classLayouts[j];
        if (clr.Parent == i) {
          result.ClassSize = clr.ClassSize;
          result.PackingSize = clr.PackingSize;
          break;
        }
      }
    }

    private void GetInterfaces(int i, int firstInterfaceIndex, InterfaceList/*!*/ interfaces) {
      InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable;
      for (int j = firstInterfaceIndex, n = intfaces.Length; j < n; j++) {
        if (intfaces[j].Class != i) continue; //TODO: break if sorted
        TypeNode ifaceT = this.DecodeAndGetTypeDefOrRefOrSpec(intfaces[j].Interface);
        Interface iface = ifaceT as Interface;
        if (iface == null) {
          iface = new Interface();
          if (ifaceT != null) {
            iface.DeclaringModule = ifaceT.DeclaringModule;
            iface.Namespace = ifaceT.Namespace;
            iface.Name = ifaceT.Name;
          }
        }
        interfaces.Add(iface);
        var implAttrs = this.GetCustomAttributesFor((j << 5)|5);
        if (implAttrs != null)
          interfaces.AddAttributes(interfaces.Count-1, implAttrs);
      }
    }

    private void RemoveTypeParametersBelongingToDeclaringType(int i, ref TypeNodeList typeParameters, TypeNode/*!*/ type) {
      NestedClassRow[] nestedClasses = tables.NestedClassTable;
      for (int j = 0, n = nestedClasses.Length; j < n; j++) { //TODO: binary search
        NestedClassRow ncr = nestedClasses[j];
        if (ncr.NestedClass == i) {
          type.DeclaringType = this.GetTypeFromDef(ncr.EnclosingClass);
          if (type.DeclaringType != null && type.DeclaringType.IsGeneric) {
            //remove type parameters that belong to declaring type from nested type's list
            if (type.templateParameters != null) {
              int icount = GetInheritedTypeParameterCount(type);
              int rcount = type.templateParameters.Count;
              if (icount >= rcount)
                type.templateParameters = null;
              else {
                TypeNodeList tpars = new TypeNodeList(rcount - icount);
                for (int k = icount; k < rcount; k++)
                  tpars.Add(type.templateParameters[k]);
                type.templateParameters = tpars;
              }
              this.currentTypeParameters = typeParameters = type.ConsolidatedTemplateParameters;
            }
          }
          break;
        }
      }
    }

    private TypeNode/*!*/ ConstructCorrectTypeNodeSubclass(int i, Identifier/*!*/ namesp, int firstInterfaceIndex, int lastInterfaceIndex,
      TypeFlags flags, InterfaceList interfaces, int baseTypeCodedIndex, bool isSystemEnum){
      TypeNode result;
      TypeNode.TypeAttributeProvider attributeProvider = new TypeNode.TypeAttributeProvider(this.GetTypeAttributes);
      TypeNode.NestedTypeProvider nestedTypeProvider = new TypeNode.NestedTypeProvider(this.GetNestedTypes);
      TypeNode.TypeMemberProvider memberProvider = new TypeNode.TypeMemberProvider(this.GetTypeMembers);
      bool isTemplateParameter = false;
#if ExtendedRuntime
      InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable;
      Interface firstInterface = null;
      Interface lastInterface = null;
      if (firstInterfaceIndex >= 0){
        firstInterface = this.GetInterfaceIfNotGenericInstance(intfaces[firstInterfaceIndex].Interface);
        if (firstInterface != null){
          lastInterface = this.GetInterfaceIfNotGenericInstance(intfaces[lastInterfaceIndex].Interface);
          isTemplateParameter = CoreSystemTypes.IsInitialized && lastInterface != null && lastInterface == ExtendedRuntimeTypes.ITemplateParameter;
        }
      }        
#endif
      if ((flags & TypeFlags.Interface) != 0){
        if (isTemplateParameter)
          result = new TypeParameter(interfaces, nestedTypeProvider, attributeProvider, memberProvider, i);
        else
          result = new Interface(interfaces, nestedTypeProvider, attributeProvider, memberProvider, i);
      }else if (isTemplateParameter){
        result = new ClassParameter(nestedTypeProvider, attributeProvider, memberProvider, i);
      }else{
        result = null;
        TypeNode baseClass = this.GetTypeIfNotGenericInstance(baseTypeCodedIndex);
        if (baseClass != null){
          if (baseClass == CoreSystemTypes.MulticastDelegate) //TODO: handle single cast delegates
            result = new DelegateNode(nestedTypeProvider, attributeProvider, memberProvider, i);
          else if (baseClass == CoreSystemTypes.Enum || baseClass.Namespace.UniqueIdKey==StandardIds.System.UniqueIdKey && baseClass.Name.UniqueIdKey == StandardIds.Enum.UniqueIdKey)
            result = new EnumNode(nestedTypeProvider, attributeProvider, memberProvider, i);
          else if (baseClass == CoreSystemTypes.ValueType &&
            !(isSystemEnum && (flags & TypeFlags.Sealed) == 0)){
#if ExtendedRuntime
            Struct st = null;
            if (firstInterface != null){
              if (namesp.UniqueIdKey == StandardIds.StructuralTypes.UniqueIdKey){
                if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TupleType)
                  st = new TupleType(nestedTypeProvider, attributeProvider, memberProvider, i);
                else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeIntersection)
                  st = new TypeIntersection(nestedTypeProvider, attributeProvider, memberProvider, i);
                else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeUnion)
                  st = new TypeUnion(nestedTypeProvider, attributeProvider, memberProvider, i);
                else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.ConstrainedType)
                  st = new ConstrainedType(nestedTypeProvider, attributeProvider, memberProvider, i);
                else
                  st = new Struct(nestedTypeProvider, attributeProvider, memberProvider, i);
              }
              else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeAlias)
                st = new TypeAlias(nestedTypeProvider, attributeProvider, memberProvider, i, false);
              else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeDefinition)
                st = new TypeAlias(nestedTypeProvider, attributeProvider, memberProvider, i, true);
            }
            if (st == null && lastInterface != null) {
              result = this.GetTypeExtensionFromDef(nestedTypeProvider, attributeProvider, memberProvider, i, baseClass, lastInterface);
            }
            else {
              result = st;
            }
            if (result == null)
#endif
              result = new Struct(nestedTypeProvider, attributeProvider, memberProvider, i);
          }
        }
        if (result == null){
#if ExtendedRuntime
          if (lastInterface != null)
            result = this.GetTypeExtensionFromDef(nestedTypeProvider, attributeProvider, memberProvider, i, baseClass, lastInterface);
          if (result == null)
#endif
            result = new Class(nestedTypeProvider, attributeProvider, memberProvider, i);
        }
      }
      result.Flags = flags;
      result.Interfaces = interfaces;
      return result;
    }
#if !MinimalReader
    private TrivialHashtable/*<Ident,TypeExtensionProvider>*//*!*/ TypeExtensionTable = new TrivialHashtable();
    delegate TypeNode TypeExtensionProvider(TypeNode.NestedTypeProvider nprovider, TypeNode.TypeAttributeProvider aprovider, TypeNode.TypeMemberProvider mprovider, TypeNode baseType, object handle);

    private static TypeNode DummyTypeExtensionProvider(TypeNode.NestedTypeProvider nprovider, TypeNode.TypeAttributeProvider aprovider, TypeNode.TypeMemberProvider mprovider, TypeNode baseType, object handle) {
      return null;
    }
    private TypeExtensionProvider/*!*/ dummyTEProvider = new TypeExtensionProvider(DummyTypeExtensionProvider);

    private TypeNode GetTypeExtensionFromDef(TypeNode.NestedTypeProvider nestedTypeProvider, TypeNode.TypeAttributeProvider attributeProvider, TypeNode.TypeMemberProvider memberProvider, object handle, TypeNode baseType, Interface/*!*/ lastInterface) {
      if (lastInterface.Namespace.UniqueIdKey == StandardIds.CciTypeExtensions.UniqueIdKey) {
        TypeExtensionProvider teprovider = (TypeExtensionProvider)TypeExtensionTable[lastInterface.Name.UniqueIdKey];
        if (teprovider == null) {
          string loc = lastInterface.DeclaringModule.Location.ToLower(CultureInfo.InvariantCulture);
          if (loc.EndsWith(".runtime.dll")) {
            loc = System.IO.Path.GetFileName(loc);
            string compilerDllName = loc.Replace(".runtime.dll", "");
            System.Reflection.Assembly rassem;
            try{
              rassem = System.Reflection.Assembly.Load(compilerDllName);
            }catch{
              HandleError(this.module, string.Format(CultureInfo.CurrentCulture, ExceptionStrings.CannotLoadTypeExtension, lastInterface.FullName, compilerDllName));
              goto ExtensionNotFound;
            }
            if (rassem == null) goto ExtensionNotFound;  
            System.Type tprov = rassem.GetType(StandardIds.CciTypeExtensions.Name+"."+lastInterface.Name.Name+"Provider");
            if (tprov == null) goto ExtensionNotFound;
            System.Reflection.MethodInfo providerMethod = tprov.GetMethod("For");
            if (providerMethod == null) goto ExtensionNotFound;
            teprovider = (TypeExtensionProvider)Delegate.CreateDelegate(typeof(TypeExtensionProvider), providerMethod);
          ExtensionNotFound: ;
            if (teprovider == null) {
              // install a not-found dummy provider
              teprovider = this.dummyTEProvider;
            }
            TypeExtensionTable[lastInterface.Name.UniqueIdKey] = teprovider;
          }
        }
        if (teprovider == null) return null;
        return teprovider(nestedTypeProvider, attributeProvider, memberProvider, baseType, handle);
      }
      return null;
    }
#endif
    private static int GetInheritedTypeParameterCount(TypeNode type){
      if (type == null) return 0;
      int n = 0;
      type = type.DeclaringType;
      while (type != null){
        n += type.templateParameters == null ? 0 : type.templateParameters.Count;
        type = type.DeclaringType;
      }
      return n;
    }
    private TypeNode/*!*/ GetTypeGlobalMemberContainerTypeFromModule(int i){
      ModuleRefRow mr = this.tables.ModuleRefTable[i-1];
      Module mod = mr.Module;
      TypeNode result = null;
      if (mod != null && mod.Types != null && mod.Types.Count > 0)
        result = mod.Types[0];
      if (result != null) return result;
      result = this.GetDummyTypeNode(Identifier.Empty, Identifier.For("<Module>"), mod, null, false);
      if (mod != null) mod.Types = new TypeNodeList(result);
      return result;
    }
    internal void GetNamespaces()
       //^ ensures this.namespaceTable != null;
    {
      TypeDefRow[] typeDefs = this.tables.TypeDefTable;
      int n = typeDefs.Length;
      TrivialHashtable nsT = this.namespaceTable = new TrivialHashtable(n);
      TrivialHashtable nsFor = new TrivialHashtable(128);
      NamespaceList nsL = this.namespaceList = new NamespaceList(n);
      for (int i = 0; i < n; i++){
        TypeDefRow typeDef = typeDefs[i];
        TrivialHashtable ns = (TrivialHashtable)nsT[typeDef.NamespaceKey];
        Namespace nSpace = (Namespace)nsFor[typeDef.NamespaceKey];
        if (ns == null){
          nsT[typeDef.NamespaceKey] = ns = new TrivialHashtable();
          nsFor[typeDef.NamespaceKey] = nSpace = new Namespace(typeDef.NamespaceId);
          nsL.Add(nSpace);
        }
        Debug.Assert(nSpace != null);
        if ((typeDef.Flags & (int)TypeFlags.VisibilityMask) == 0)
          ns[typeDef.NameKey] = i+1;
        else if ((typeDef.Flags & (int)TypeFlags.VisibilityMask) == 1){
          nSpace.isPublic = true;
          ns[typeDef.NameKey] = i+1;
        }
      }
    }
    private TypeNode GetTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
      try{
        if (this.namespaceTable == null) this.GetNamespaces();
        //^ assert this.namespaceTable != null;
        TrivialHashtable nsTable = (TrivialHashtable)this.namespaceTable[Namespace.UniqueIdKey];
        if (nsTable == null) return this.GetForwardedTypeFromName(Namespace, name);
        object ti = nsTable[name.UniqueIdKey];
        if (ti == null) return this.GetForwardedTypeFromName(Namespace, name);
        TypeNode t = this.GetTypeFromDef((int)ti);
        return t;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return null;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return null;
      }
#else
      }finally{}
#endif
    }
    private TypeNode GetForwardedTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
      ExportedTypeRow[] exportedTypes = this.tables.ExportedTypeTable;
      for (int i = 0, n = exportedTypes == null ? 0 : exportedTypes.Length; i < n; i++) {
        ExportedTypeRow etr = exportedTypes[i];
        if ((etr.Flags & (int)TypeFlags.Forwarder) == 0) continue;
        if (this.tables.GetString(etr.TypeNamespace) != Namespace.Name ||
            this.tables.GetString(etr.TypeName) != name.Name) continue;
        int index = etr.Implementation >> 2;
        AssemblyRefRow arr = this.tables.AssemblyRefTable[index - 1];
        return arr.AssemblyReference.Assembly.GetType(Namespace, name);
      }
      return this.GetReplacedTypeFromName(Namespace, name);
    }
    private TypeNode GetReplacedTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
#if !MinimalReader
      if (this.module.ContainingAssembly == null || (this.module.ContainingAssembly.Flags & AssemblyFlags.ContainsForeignTypes) == 0) return null;
      if (!SystemTypes.Initialized || this.module.ContainingAssembly == null) return null;
      int nsKey = Namespace.UniqueIdKey;
      int nKey = name.UniqueIdKey;
      if (nsKey == StandardIds.WindowsFoundationMetadata.UniqueIdKey) {
        if (nKey == SystemTypes.AttributeUsageAttribute.Name.UniqueIdKey) return SystemTypes.AttributeUsageAttribute;
        if (nKey == SystemTypes.AttributeTargets.Name.UniqueIdKey) return SystemTypes.AttributeTargets;
      } else if (nsKey == StandardIds.WindowsUI.UniqueIdKey) {
        if (nKey == SystemTypes.Color.Name.UniqueIdKey && SystemTypes.Color.DeclaringModule.Location != "unknown:location") return SystemTypes.Color;
      } else if (nsKey == StandardIds.WindowsFoundation.UniqueIdKey) {
        if (nKey == SystemTypes.DateTime.Name.UniqueIdKey) return SystemTypes.DateTimeOffset;
        if (SystemTypes.EventHandler1 != null && nKey == SystemTypes.EventHandler1.Name.UniqueIdKey) return SystemTypes.EventHandler1;
        if (nKey == SystemTypes.EventRegistrationToken.Name.UniqueIdKey) return SystemTypes.EventRegistrationToken;
        if (nKey == StandardIds.HResult.UniqueIdKey) return SystemTypes.Exception;
        if (nKey == StandardIds.IReference1.UniqueIdKey) return SystemTypes.GenericNullable;
        if (nKey == SystemTypes.Point.Name.UniqueIdKey) return SystemTypes.Point;
        if (nKey == SystemTypes.Rect.Name.UniqueIdKey) return SystemTypes.Rect;
        if (nKey == SystemTypes.Size.Name.UniqueIdKey) return SystemTypes.Size;
        if (nKey == SystemTypes.TimeSpan.Name.UniqueIdKey) return SystemTypes.TimeSpan;
        if (nKey == SystemTypes.Uri.Name.UniqueIdKey) return SystemTypes.Uri;
        if (nKey == StandardIds.IClosable.UniqueIdKey) return SystemTypes.IDisposable;
      } else if (nsKey == StandardIds.WindowsFoundationCollections.UniqueIdKey) {
        if (nKey == StandardIds.IIterable1.UniqueIdKey) return SystemTypes.GenericIEnumerable;
        if (nKey == StandardIds.IVector1.UniqueIdKey) return SystemTypes.GenericIList;
        if (nKey == StandardIds.IVectorView1.UniqueIdKey) return SystemTypes.GenericIReadOnlyList;
        if (nKey == StandardIds.IMap2.UniqueIdKey) return SystemTypes.GenericIDictionary;
        if (nKey == StandardIds.IMapView2.UniqueIdKey) return SystemTypes.GenericIReadOnlyDictionary;
        if (nKey == StandardIds.IKeyValuePair2.UniqueIdKey) return SystemTypes.GenericKeyValuePair;
      } else if (nsKey == StandardIds.WindowsUIXaml.UniqueIdKey) {
        if (nKey == SystemTypes.CornerRadius.Name.UniqueIdKey && SystemTypes.CornerRadius.DeclaringModule.Location != "unknown:location") return SystemTypes.CornerRadius;
        if (nKey == SystemTypes.Duration.Name.UniqueIdKey && SystemTypes.Duration.DeclaringModule.Location != "unknown:location") return SystemTypes.Duration;
        if (SystemTypes.DurationType != null && nKey == SystemTypes.DurationType.Name.UniqueIdKey) return SystemTypes.DurationType;
        if (nKey == SystemTypes.GridLength.Name.UniqueIdKey && SystemTypes.GridLength.DeclaringModule.Location != "unknown:location") return SystemTypes.GridLength;
        if (SystemTypes.GridUnitType != null && nKey == SystemTypes.GridUnitType.Name.UniqueIdKey) return SystemTypes.GridUnitType;
        if (nKey == SystemTypes.Thickness.Name.UniqueIdKey && SystemTypes.Thickness.DeclaringModule.Location != "unknown:location") return SystemTypes.Thickness;
      } else if (nsKey == StandardIds.WindowsUIXamlData.UniqueIdKey) {
        if (nKey == SystemTypes.INotifyPropertyChanged.Name.UniqueIdKey && SystemTypes.INotifyPropertyChanged.DeclaringModule.Location != "unknown:location") return SystemTypes.INotifyPropertyChanged;
        if (nKey == SystemTypes.PropertyChangedEventHandler.Name.UniqueIdKey && SystemTypes.PropertyChangedEventHandler.DeclaringModule.Location != "unknown:location") return SystemTypes.PropertyChangedEventHandler;
        if (nKey == SystemTypes.PropertyChangedEventArgs.Name.UniqueIdKey && SystemTypes.PropertyChangedEventArgs.DeclaringModule.Location != "unknown:location") return SystemTypes.PropertyChangedEventArgs;
      } else if (nsKey == StandardIds.WindowsUIXamlInput.UniqueIdKey) {
        if (nKey == StandardIds.ICommand.UniqueIdKey) return SystemTypes.ICommand;
      } else if (nsKey == StandardIds.WindowsUIXamlInterop.UniqueIdKey) {
        if (nKey == StandardIds.IBindableIterable.UniqueIdKey) return SystemTypes.IBindableIterable;
        if (nKey == StandardIds.IBindableVector.UniqueIdKey) return SystemTypes.IBindableVector;
        if (nKey == StandardIds.INotifyCollectionChanged.UniqueIdKey) return SystemTypes.INotifyCollectionChanged;
        if (nKey == StandardIds.NotifyCollectionChangedAction.UniqueIdKey) return SystemTypes.NotifyCollectionChangedAction;
        if (nKey == StandardIds.NotifyCollectionChangedEventArgs.UniqueIdKey) return SystemTypes.NotifyCollectionChangedEventArgs;
        if (nKey == StandardIds.NotifyCollectionChangedEventHandler.UniqueIdKey) return SystemTypes.NotifyCollectionChangedEventHandler;
        if (nKey == StandardIds.TypeName.UniqueIdKey) return SystemTypes.Type;
      } else if (nsKey == StandardIds.WindowsUIXamlControlsPrimitives.UniqueIdKey) {
        if (nKey == SystemTypes.GeneratorPosition.Name.UniqueIdKey && SystemTypes.GeneratorPosition.DeclaringModule.Location != "unknown:location") return SystemTypes.GeneratorPosition;
      } else if (nsKey == StandardIds.WindowsUIXamlMedia.UniqueIdKey) {
        if (nKey == SystemTypes.Matrix.Name.UniqueIdKey && SystemTypes.Matrix.DeclaringModule.Location != "unknown:location") return SystemTypes.Matrix;
      } else if (nsKey == StandardIds.WindowsUIXamlMediaAnimation.UniqueIdKey) {
        if (nKey == SystemTypes.KeyTime.Name.UniqueIdKey && SystemTypes.KeyTime.DeclaringModule.Location != "unknown:location") return SystemTypes.KeyTime;
        if (nKey == SystemTypes.RepeatBehavior.Name.UniqueIdKey && SystemTypes.KeyTime.DeclaringModule.Location != "unknown:location") return SystemTypes.RepeatBehavior;
        if (SystemTypes.RepeatBehaviorType != null && nKey == SystemTypes.RepeatBehaviorType.Name.UniqueIdKey) return SystemTypes.RepeatBehaviorType;
      } else if (nsKey == StandardIds.WindowsUIXamlMediaMedia3D.UniqueIdKey) {
        if (nKey == SystemTypes.Matrix3D.Name.UniqueIdKey && SystemTypes.Matrix3D.DeclaringModule.Location != "unknown:location") return SystemTypes.Matrix3D;
      }
#endif
      return null;
    }
    internal bool IsValidTypeName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
      try{
        if (this.namespaceTable == null) this.GetNamespaces();
        //^ assert this.namespaceTable != null;
        TrivialHashtable nsTable = (TrivialHashtable)this.namespaceTable[Namespace.UniqueIdKey];
        if (nsTable == null) return false;
        return nsTable[name.UniqueIdKey] != null;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return false;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return false;
      }
#else
      }finally{}
#endif
    }
    internal TypeNode/*!*/ GetTypeFromRef(int i) {
      return this.GetTypeFromRef(i, false);
    }
    internal TypeNode/*!*/ GetTypeFromRef(int i, bool expectStruct) {
      TypeRefRow[] trtable = this.tables.TypeRefTable;
      TypeRefRow trr = trtable[i-1];
      TypeNode result = trr.Type;
      if (result != null) return result;
      Identifier name = tables.GetIdentifier(trr.Name);
      Identifier namesp = tables.GetIdentifier(trr.Namespace);
      int resolutionScope = trr.ResolutionScope;
      Module declaringModule = null;
      TypeNode declaringType = null;
      int index = resolutionScope >> 2;
      switch (resolutionScope & 0x3){
        case 0:
          declaringModule = this.module;
          //^ assume declaringModule != null;
          result = declaringModule.GetType(namesp, name);
          //REVIEW: deal with case where ref is in same (multi-module) assembly, but not the current module? index == 0
          break;
        case 1: 
          declaringModule = this.tables.ModuleRefTable[index-1].Module;
          if (declaringModule != null)
            result = declaringModule.GetType(namesp, name);
          break; 
        case 2:
          if (index > 0)
            declaringModule = this.tables.AssemblyRefTable[index - 1].AssemblyReference.Assembly;
          if (declaringModule != null)
            result = declaringModule.GetType(namesp, name);
          break;
        case 3: 
          declaringType = this.GetTypeFromRef(index);
          declaringModule = declaringType.DeclaringModule;
          if (namesp == null || namesp.length == 0)
            result = (TypeNode)declaringType.GetMembersNamed(name)[0];
          else
            result = (TypeNode)declaringType.GetMembersNamed(Identifier.For(namesp.Name+"."+name.Name))[0];
          break;
        default: 
          declaringModule = this.module;
          break;
      }
      if (result == null)
        result = this.GetDummyTypeNode(namesp, name, declaringModule, declaringType, expectStruct);
      trtable[i-1].Type = result;
      if (!Reader.CanCacheTypeNode(result))
        trtable[i-1].Type = null;
      return result;
    }
    private TypeNode/*!*/ GetDummyTypeNode(Identifier namesp, Identifier name, Module declaringModule, TypeNode declaringType, bool expectStruct) {
      TypeNode result = null;
      if (this.module != null) {
        string modName = declaringModule == null ? "" : declaringModule.Name == null ? "" : declaringModule.Name.ToString();
        string context = declaringType != null ? declaringType.FullName: (namesp!=null)?namesp.Name:null;
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveTypeReference,
          "["+modName+"]"+context+"."+name));
      }
      result = expectStruct ? (TypeNode)new Struct() : (TypeNode)new Class();
      if (name != null && name.ToString().StartsWith("I") && name.ToString().Length > 1 && char.IsUpper(name.ToString()[1]))
        result = new Interface();
      result.Flags |= TypeFlags.Public;
      result.Name = name;
      result.Namespace = namesp;
      if (declaringType != null) {
        result.DeclaringType = declaringType;
        result.DeclaringType.DeclaringModule = declaringType.DeclaringModule;
        declaringType.Members.Add(result);
      } else {
        if (declaringModule == null) declaringModule = this.module;
        //^ assume declaringModule != null;
        result.DeclaringModule = declaringModule;
        if (declaringModule.types != null)
          declaringModule.types.Add(result);
      }
      return result;
    }
    private bool TypeSpecIsClass(int i){
      TypeSpecRow tsr = this.tables.TypeSpecTable[i-1];
      if (tsr.Type != null) return tsr.Type is Class;
      this.tables.GetSignatureLength(tsr.Signature);
      return this.TypeSignatureIsClass(this.tables.GetNewCursor());
    }
    internal TypeNode/*!*/ GetTypeFromSpec(int i) {
      TypeSpecRow tsr = this.tables.TypeSpecTable[i-1];
      if (tsr.Type != null) return tsr.Type;
      this.tables.GetSignatureLength(tsr.Signature);
      bool pinned = false;
      bool isTypeArgument = false;
      TypeNode result = this.ParseTypeSignature(this.tables.GetNewCursor(), ref pinned, ref isTypeArgument);
      if (result == null) result = new Class();
      //Get custom attributes
      AttributeList attributes = this.GetCustomAttributesFor((i << 5) | 13);
      if (attributes != null && attributes.Count > 0) {
        //Append attributes "inherited" from template to metadata attributes
        AttributeList templAttributes = result.Attributes;
        for (int j = 0, n = templAttributes == null ? 0 : templAttributes.Count; j < n; j++) {
          AttributeNode attr = result.Attributes[j];
          if (attr == null) continue;
          attributes.Add(attr);
        }
        result.Attributes = attributes;
      }
#if ExtendedRuntime
      for (int j = 0, n = attributes.Count; j < n; j++) {
        if (attributes[j].Type == SystemTypes.NotNullGenericArgumentsAttribute) {
          Literal l = (Literal)attributes[j].Expressions[0];
          string s = (string)l.Value;
          TypeNodeList ts = new TypeNodeList(s.Length);
          for (int k = 0, m = s.Length; k < m; k++) {
            if (s[k] == '!')
              ts.Add(OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, result.ConsolidatedTemplateArguments[k]));
            else
              ts.Add(result.ConsolidatedTemplateArguments[k]);
          }
          result = result.Template.GetGenericTemplateInstance(this.module, ts);
          //^ assume result != null;
        }
      }
#endif
      if (!isTypeArgument && Reader.CanCacheTypeNode(result))
        this.tables.TypeSpecTable[i-1].Type = result;
      return result;
    }
    private static bool CanCacheTypeNode(TypeNode/*!*/ type) {
#if WHIDBEY
      if (!type.IsGeneric && (type.Template == null || !type.IsNotFullySpecialized) &&
      type.NodeType != NodeType.TypeParameter && type.NodeType != NodeType.ClassParameter &&
      type.NodeType != NodeType.InterfaceExpression) {
        TypeNodeList elementTypes = type.StructuralElementTypes;
        for (int i = 0, n = elementTypes == null ? 0 : elementTypes.Count; i < n; i++)
          if (!CanCacheTypeNode(type.StructuralElementTypes[i])) return false;
        return true;
      }
      return false;
#else
      return true;
#endif
    }
    private static Module GetNestedModule(Module module, string modName, ref string modLocation){
      if (module == null || modName == null){Debug.Assert(false); return null;}
      Module mod = module.GetNestedModule(modName);
      if (mod == null){
        if (module.Location != null)
          modLocation = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(module.Location), modName);
        if (modLocation != null && System.IO.File.Exists(modLocation)){
          mod = Module.GetModule(modLocation);
          if (mod != null){
            mod.ContainingAssembly = module.ContainingAssembly;
            module.ModuleReferences.Add(new ModuleReference(modName, mod));
          }
        }
      }
      if (mod == null){
        HandleError(module, String.Format(CultureInfo.CurrentCulture,
          ExceptionStrings.CouldNotFindReferencedModule,modLocation));
        mod = new Module();
        mod.Name = modName;
        mod.ContainingAssembly = module.ContainingAssembly;
        mod.Kind = ModuleKindFlags.DynamicallyLinkedLibrary;
      }
      return mod;
    }
    private void GetTypeList(Module/*!*/ module) {
      TypeNodeList types = new TypeNodeList();
      TypeDefRow[] typeDefs = this.tables.TypeDefTable;
      for (int i = 0, n = typeDefs.Length; i < n; i++){
        TypeNode t = this.GetTypeFromDef(i+1);
        if (t != null && t.DeclaringType == null) types.Add(t);
      }
      module.Types = types;
      AssemblyNode assem = module as AssemblyNode;
      if (assem == null) return;
      types = new TypeNodeList();
      ExportedTypeRow[] exportedTypes = this.tables.ExportedTypeTable;
      for (int i = 0, n = exportedTypes.Length; i < n; i++){
        ExportedTypeRow etr = exportedTypes[i];
        Identifier nameSpace = Identifier.For(this.tables.GetString(etr.TypeNamespace));
        Identifier typeName = Identifier.For(this.tables.GetString(etr.TypeName));
        TypeNode exportedType = null;
        switch (etr.Implementation & 0x3){
          case 0:
            string modName = this.tables.GetString(this.tables.FileTable[(etr.Implementation >> 2)-1].Name);
            string modLocation = modName;
            Module mod = GetNestedModule(assem, modName, ref modLocation);
            if (mod == null){Debug.Assert(false); break;}
            exportedType = mod.GetType(nameSpace, typeName);
            if (exportedType == null){
              HandleError(assem, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.CouldNotFindExportedTypeInModule, nameSpace+"."+typeName, modLocation));
              exportedType = new Class();
              exportedType.Name = typeName;
              exportedType.Namespace = nameSpace;
              exportedType.Flags = TypeFlags.Class|TypeFlags.Public;
              exportedType.DeclaringModule = mod;
            }
            break;
          case 1:
            AssemblyReference aref = this.tables.AssemblyRefTable[(etr.Implementation >> 2)-1].AssemblyReference;
            if (aref == null){
              HandleError(assem, ExceptionStrings.BadMetadataInExportTypeTableNoSuchAssemblyReference);
              aref = new AssemblyReference("dummy assembly for bad reference");
            }
            AssemblyNode a = aref.Assembly;
            if (a == null){Debug.Assert(false); continue;}
            exportedType = a.GetType(nameSpace, typeName);
            if (exportedType == null){
              HandleError(assem, String.Format(CultureInfo.CurrentCulture, 
                ExceptionStrings.CouldNotFindExportedTypeInAssembly, nameSpace+"."+typeName, a.StrongName));
              exportedType = new Class();
              exportedType.Name = typeName;
              exportedType.Namespace = nameSpace;
              exportedType.Flags = TypeFlags.Class|TypeFlags.Public;
              exportedType.DeclaringModule = a;
            }
            break;
          case 2:
            TypeNode parentType = types[(etr.Implementation >> 2)-1];
            if (parentType == null){
              HandleError(assem, ExceptionStrings.BadMetadataInExportTypeTableNoSuchParentType);
              parentType = new Class();
              parentType.DeclaringModule = this.module;
              parentType.Name = Identifier.For("Missing parent type");
            }
            exportedType = parentType.GetNestedType(typeName);
            if (exportedType == null){
              HandleError(assem, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.CouldNotFindExportedNestedTypeInType, typeName, parentType.FullName));
              exportedType = new Class();
              exportedType.Name = typeName;
              exportedType.Flags = TypeFlags.Class|TypeFlags.NestedPublic;
              exportedType.DeclaringType = parentType;
              exportedType.DeclaringModule = parentType.DeclaringModule;
            }
            break;
        }
        types.Add(exportedType);
      }
      assem.ExportedTypes = types;
    }
    private void GetNestedTypes(TypeNode/*!*/ type, object/*!*/ handle) {
      type.nestedTypes = null;
      TypeNodeList result = new TypeNodeList();
#if !FxCop
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNode savedCurrentType = this.currentType;
#endif
      try{
        if (type.IsGeneric){
          if (type.templateParameters == null) type.templateParameters = new TypeNodeList(0);
          this.currentTypeParameters = type.ConsolidatedTemplateParameters;
        }
        this.currentType = type;
        TypeNode declaringType = type.DeclaringType;
        while (this.currentTypeParameters == null && declaringType != null){
          if (declaringType.IsGeneric) {
            if (declaringType.templateParameters == null) declaringType.templateParameters = new TypeNodeList(0);
            this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters;
          }
          declaringType = declaringType.DeclaringType;
        }
        MetadataReader tables = this.tables;
        int typeTableIndex = (int)handle;
        TypeDefRow[] typeDefs = tables.TypeDefTable;
        int n = typeDefs.Length;
        if (typeTableIndex < 1 || typeTableIndex > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        NestedClassRow[] nestedClasses = tables.NestedClassTable;
        n = nestedClasses.Length;
        for (int i = 0; i < n; i++){ //TODO: binary lookup
          NestedClassRow ncr = nestedClasses[i];
          if (ncr.EnclosingClass != typeTableIndex) continue;
          TypeNode t = this.GetTypeFromDef(ncr.NestedClass);
          if (t != null) {
            if (type.nestedTypes != null) return; //A recursive call to GetNestedTypes has already done the deed
            t.DeclaringType = type;
            if ((t.Flags & TypeFlags.RTSpecialName) == 0 || t.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey)
              result.Add(t);
          } else {
            throw new InvalidMetadataException("Invalid nested class row");
          }
        }
        type.nestedTypes = result;
#if !FxCop
      }catch (Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
      }
      finally{
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentType = savedCurrentType;
      }
#else
      }finally{}
#endif
    }
    private void GetTypeMembers(TypeNode/*!*/ type, object/*!*/ handle) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNode savedCurrentType = this.currentType;
      try{
        MetadataReader tables = this.tables;
        int typeTableIndex = (int)handle;
        TypeDefRow[] typeDefs = tables.TypeDefTable;
        FieldRow[] fieldDefs = tables.FieldTable;
        FieldPtrRow[] fieldPtrs = tables.FieldPtrTable;
        MethodRow[] methodDefs = tables.MethodTable;
        MethodPtrRow[] methodPtrs = tables.MethodPtrTable;
        EventMapRow[] eventMaps = tables.EventMapTable;
        EventRow[] eventDefs = tables.EventTable;
        EventPtrRow[] eventPtrs = tables.EventPtrTable;
        MethodImplRow[] methodImpls = tables.MethodImplTable;
        PropertyMapRow[] propertyMaps = tables.PropertyMapTable;
        PropertyPtrRow[] propertyPtrs = tables.PropertyPtrTable;
        PropertyRow[] propertyDefs = this.tables.PropertyTable;
        NestedClassRow[] nestedClasses = tables.NestedClassTable;
        int n = typeDefs.Length;
        if (typeTableIndex < 1 || typeTableIndex > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        TypeDefRow td = typeDefs[typeTableIndex-1];
        if (type != td.Type) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        //Get type members
        if (type.IsGeneric){
          if (type.templateParameters == null) type.templateParameters = new TypeNodeList(0);
          this.currentTypeParameters = type.ConsolidatedTemplateParameters;
        }
        this.currentType = type;
        TypeNode declaringType = type.DeclaringType;
        while (this.currentTypeParameters == null && declaringType != null){
          if (declaringType.IsGeneric){
            if (declaringType.templateParameters == null) declaringType.templateParameters = new TypeNodeList(0);
            this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters;
          }
          declaringType = declaringType.DeclaringType;
        }
        type.members = new MemberList();
        n = nestedClasses.Length;
        for (int i = 0; i < n; i++){
          NestedClassRow ncr = nestedClasses[i];
          if (ncr.EnclosingClass != typeTableIndex) continue;
          TypeNode t = this.GetTypeFromDef(ncr.NestedClass);
          if (t != null){
            t.DeclaringType = type;
            if ((t.Flags & TypeFlags.RTSpecialName) == 0 || t.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey)
              type.Members.Add(t);
          }
        }
        n = typeDefs.Length;
        int m = fieldDefs.Length;
        int start = td.FieldList;
        int end = m+1; if (typeTableIndex < n) end = typeDefs[typeTableIndex].FieldList;
        if (type is EnumNode) this.GetUnderlyingTypeOfEnumNode((EnumNode)type, fieldDefs, fieldPtrs, start, end);
        this.AddFieldsToType(type, fieldDefs, fieldPtrs, start, end);
        m = methodDefs.Length;
        start = td.MethodList;
        end = m+1; if (typeTableIndex < n) end = typeDefs[typeTableIndex].MethodList;
        this.AddMethodsToType(type, methodPtrs, start, end);
        n = propertyMaps.Length;
        m = propertyDefs.Length;
        for (int i = 0; i < n; i++){ //TODO: binary search
          PropertyMapRow pm = propertyMaps[i];
          if (pm.Parent != typeTableIndex) continue;
          start = pm.PropertyList;
          end = m+1; if (i < n-1) end = propertyMaps[i+1].PropertyList;
          this.AddPropertiesToType(type, propertyDefs, propertyPtrs, start, end);
        }
        n = eventMaps.Length;
        m = eventDefs.Length;
        for (int i = 0; i < n; i++){ //TODO: binary search
          EventMapRow em = eventMaps[i];
          if (em.Parent != typeTableIndex) continue;
          start = em.EventList;
          end = m+1; if (i < n-1) end = eventMaps[i+1].EventList;
          this.AddEventsToType(type, eventDefs, eventPtrs, start, end);
        }
        n = methodImpls.Length;
        for (int i = 0; i < n; i++){ //TODO: binary search
          MethodImplRow mir = methodImpls[i];
          if (mir.Class != typeTableIndex) continue;
          Method implementer = this.GetMethodDefOrRef(mir.MethodBody);
          if (implementer == null) continue;
          MethodList implementedInterfaceMethods = implementer.ImplementedInterfaceMethods;
          if (implementedInterfaceMethods == null)
            implementedInterfaceMethods = implementer.ImplementedInterfaceMethods = new MethodList();
          TypeNodeList savedMethodTypeParameters = this.currentMethodTypeParameters;
          this.currentMethodTypeParameters = implementer.TemplateParameters;
          implementedInterfaceMethods.Add(this.GetMethodDefOrRef(mir.MethodDeclaration));
          this.currentMethodTypeParameters = savedMethodTypeParameters;
        }
        this.currentTypeParameters = savedCurrentTypeParameters;
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        type.Members = new MemberList(0);
      }
      finally{
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentType = savedCurrentType;
      }
#else
      }finally{}
#endif
    }
    private void GetTypeAttributes(TypeNode/*!*/ type, object/*!*/ handle) {
      Debug.Assert(TypeNode.IsCompleteTemplate(type));
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      try{
        MetadataReader tables = this.tables;
        int typeTableIndex = (int)handle;
        TypeDefRow[] typeDefs = tables.TypeDefTable;
        int n = typeDefs.Length;
        if (typeTableIndex < 1 || typeTableIndex > n) 
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        TypeDefRow td = typeDefs[typeTableIndex-1];
        if (type != td.Type) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        //Get custom attributes   
        type.Attributes = this.GetCustomAttributesNonNullFor((typeTableIndex << 5)|3);
        this.currentTypeParameters = savedCurrentTypeParameters;
        //Get security attributes
        if ((type.Flags & TypeFlags.HasSecurity) != 0)
          type.SecurityAttributes = this.GetSecurityAttributesFor((typeTableIndex << 2)|0);
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        type.Attributes = new AttributeList(0);
        this.currentTypeParameters = savedCurrentTypeParameters;
      }
#else
      }finally{}
#endif
    }
    private void GetTypeParameterAttributes(TypeNode/*!*/ type, object/*!*/ handle) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      try {
        MetadataReader tables = this.tables;
        int genericParamIndex = (int)handle;
        GenericParamRow[] genParDefs = tables.GenericParamTable;
        int n = genParDefs.Length;
        if (genericParamIndex < 1 || genericParamIndex > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        GenericParamRow td = genParDefs[genericParamIndex-1];
        //Get custom attributes   
        type.Attributes = this.GetCustomAttributesNonNullFor((genericParamIndex << 5)|19);
        this.currentTypeParameters = savedCurrentTypeParameters;
#if !FxCop
      } catch (Exception e) {
        if (this.module != null) {
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        type.Attributes = new AttributeList(0);
        this.currentTypeParameters = savedCurrentTypeParameters;
      }
#else
      }finally{}
#endif
    }
    private TypeNodeList/*!*/ ParseTypeList(MemoryCursor/*!*/ sigReader) {
      int n = sigReader.ReadCompressedInt();
      TypeNodeList result = new TypeNodeList(n);
      for (int i = 0; i < n; i++){
        TypeNode t = this.ParseTypeSignature(sigReader);
        if (t == null || t == Struct.Dummy){
          //Can happen when dealing with a primitive type that implements an interface that references the primitive type.
          //For example, System.String implements IComparable<System.String>.
          if (this.currentType != null && !CoreSystemTypes.Initialized)
            t = this.currentType;
          else{
            Debug.Assert(false);
            t = new TypeParameter();
            t.Name = Identifier.For("Bad type parameter in position "+i);
            t.DeclaringModule = this.module;
          }
        }
        result.Add(t);
      }
      return result;
    }
    private bool TypeSignatureIsClass(MemoryCursor/*!*/ sigReader) {
      ElementType tok = (ElementType)sigReader.ReadCompressedInt();
      switch(tok){
        case ElementType.Pinned:
        case ElementType.Pointer: 
        case ElementType.Reference: 
          return this.TypeSignatureIsClass(sigReader);
        case ElementType.OptionalModifier:
        case ElementType.RequiredModifier:
          sigReader.ReadCompressedInt();
          return this.TypeSignatureIsClass(sigReader);
        case ElementType.Class: 
          return true;// [maf] counter intuitive, but this is used to determine if a type parameter is constrained to be a class. If the type parameter derives from an interface type, then it is not constrained, but the interface type has that Elementtype Class
        case ElementType.GenericTypeInstance: 
          return this.TypeSignatureIsClass(sigReader);
        case ElementType.TypeParameter: {
            int pnum = sigReader.ReadCompressedInt();
            if (this.currentTypeParameters != null && this.currentTypeParameters.Count > pnum) {
              TypeNode tPar = this.currentTypeParameters[pnum];
              return tPar != null && tPar is Class;
            }
            return false;
          }
        case ElementType.MethodParameter: {
            int pnum = sigReader.ReadCompressedInt();
            if (this.currentMethodTypeParameters != null && this.currentMethodTypeParameters.Count > pnum) {
              TypeNode tPar = this.currentMethodTypeParameters[pnum];
              return tPar != null && tPar is Class;
            }
            return false;
          }
        default:
          return false;
      }
    }
    private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader) {
      bool junk = false;
      return this.ParseTypeSignature(sigReader, ref junk, ref junk);
    }
    private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader, ref bool pinned) {
      bool junk = false;
      return this.ParseTypeSignature(sigReader, ref pinned, ref junk);
    }
    private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader, ref bool pinned, ref bool isTypeArgument) {
      TypeNode elementType;
      ElementType tok = (ElementType)sigReader.ReadCompressedInt();
      if (tok == ElementType.Pinned){
        pinned = true;
        tok = (ElementType)sigReader.ReadCompressedInt();
      }
      switch(tok){
        case ElementType.Boolean: return CoreSystemTypes.Boolean;
        case ElementType.Char: return CoreSystemTypes.Char;
        case ElementType.Double: return CoreSystemTypes.Double;
        case ElementType.Int16: return CoreSystemTypes.Int16;
        case ElementType.Int32: return CoreSystemTypes.Int32;
        case ElementType.Int64: return CoreSystemTypes.Int64;
        case ElementType.Int8: return CoreSystemTypes.Int8;
        case ElementType.IntPtr: return CoreSystemTypes.IntPtr;
        case ElementType.BoxedEnum:
        case ElementType.Object: return CoreSystemTypes.Object;
        case ElementType.Single: return CoreSystemTypes.Single;
        case ElementType.String: return CoreSystemTypes.String;
        case ElementType.DynamicallyTypedReference : return CoreSystemTypes.DynamicallyTypedReference;
        case ElementType.UInt16: return CoreSystemTypes.UInt16;
        case ElementType.UInt32: return CoreSystemTypes.UInt32;
        case ElementType.UInt64: return CoreSystemTypes.UInt64;
        case ElementType.UInt8: return CoreSystemTypes.UInt8;
        case ElementType.UIntPtr: return CoreSystemTypes.UIntPtr;
        case ElementType.Void: return CoreSystemTypes.Void;
        case ElementType.Pointer:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          if (elementType == null) return null;
          return elementType.GetPointerType();
        case ElementType.Reference:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          return elementType.GetReferenceType();
        case ElementType.FunctionPointer:
          return this.ParseFunctionPointer(sigReader);
        case ElementType.OptionalModifier:
        case ElementType.RequiredModifier:
          TypeNode modifier = this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt());
          if (modifier == null) modifier = CoreSystemTypes.Object;
          TypeNode modified = this.ParseTypeSignature(sigReader, ref pinned);
          if (modified == null) modified = CoreSystemTypes.Object;
          if (modified == null || modified == null) return null;
          if (tok == ElementType.RequiredModifier)
            return RequiredModifier.For(modifier, modified);
          else
            return OptionalModifier.For(modifier, modified);
        case ElementType.Class:
          return this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt());
        case ElementType.ValueType:
          return this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt(), true);
        case ElementType.TypeParameter:
          TypeNode tPar = null;
          int pnum = sigReader.ReadCompressedInt();
          if (this.currentTypeParameters != null && this.currentTypeParameters.Count > pnum)
            tPar = this.currentTypeParameters[pnum];
          if (tPar == null){
            HandleError(this.module, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.BadTypeParameterInPositionForType, pnum, this.currentType == null ? "" : this.currentType.FullName));
            tPar = new TypeParameter();
            tPar.Name = Identifier.For("Bad type parameter in position "+pnum);
            tPar.DeclaringModule = this.module;
          }
          isTypeArgument = true;
          return tPar;
        case ElementType.MethodParameter:
          TypeNode mTPar = null;
          pnum = sigReader.ReadCompressedInt();
          if (this.currentMethodTypeParameters != null && this.currentMethodTypeParameters.Count > pnum)
            mTPar = this.currentMethodTypeParameters[pnum];
          if (mTPar == null){
            HandleError(this.module, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.BadMethodTypeParameterInPosition, pnum));
            mTPar = new MethodTypeParameter();
            mTPar.Name = Identifier.For("Bad method type parameter in position "+pnum);
          }
          isTypeArgument = true;
          return mTPar;
        case ElementType.GenericTypeInstance:
          TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
          TypeNode template = this.ParseTypeSignature(sigReader, ref pinned);
          this.currentTypeParameters = savedCurrentTypeParameters;
          if (template == null) return null;
          if (template.ConsolidatedTemplateParameters == null) {
            //The template could not be resolved, so we have a dummy type that has not yet been instantiated
            //Now that it is being instantiated we know how many template parameters it has, we can dummy up some template parameters
            template.IsGeneric = true;
            template.templateParameters = new TypeNodeList();
            for (int i = 0, n = sigReader.Byte(0); i < n; i++)
              template.templateParameters.Add(new TypeParameter());
          }
          if (CoreSystemTypes.Initialized){
            if (this.currentTypeParameters == null || this.currentTypeParameters.Count == 0)
              this.currentTypeParameters = template.ConsolidatedTemplateParameters;
            TypeNodeList genArgs = this.ParseTypeList(sigReader);
            if (this.module == null) return null;
            TypeNode genInst = template.GetGenericTemplateInstance(this.module, genArgs);
            this.currentTypeParameters = savedCurrentTypeParameters;
            return genInst;
          }
          InterfaceExpression ifaceExpr = new InterfaceExpression(null);
          ifaceExpr.Template = template;
          ifaceExpr.Namespace = template.Namespace;
          ifaceExpr.Name = template.Name;
          ifaceExpr.TemplateArguments = this.ParseTypeList(sigReader);
          this.currentTypeParameters = savedCurrentTypeParameters;
          return ifaceExpr;
        case ElementType.SzArray:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          if (elementType == null) return null;
          return elementType.GetArrayType(1);
        case ElementType.Array:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          if (elementType == null) return null;
          int rank = sigReader.ReadCompressedInt();
          int numSizes = sigReader.ReadCompressedInt();
          int[] sizes = new int[numSizes];
          for (int i = 0; i < numSizes; i++) sizes[i] = sigReader.ReadCompressedInt();
          int numLoBounds = sigReader.ReadCompressedInt();
          int[] loBounds = new int[numLoBounds];
          for (int i = 0; i < numLoBounds; i++) loBounds[i] = sigReader.ReadCompressedInt();
          return elementType.GetArrayType(rank, numSizes, numLoBounds, sizes, loBounds);
        case ElementType.Sentinel: return null;
        case ElementType.Type: return CoreSystemTypes.Type;
        case ElementType.Enum: return this.GetTypeFromSerializedName(ReadSerString(sigReader));
      }
      throw new InvalidMetadataException(ExceptionStrings.MalformedSignature);
    }
    private FunctionPointer/*!*/ ParseFunctionPointer(MemoryCursor/*!*/ sigReader) {
      CallingConventionFlags convention = (CallingConventionFlags)sigReader.ReadByte();
      int n = sigReader.ReadCompressedInt();
      TypeNode returnType = this.ParseTypeSignature(sigReader);
      if (returnType == null) returnType = CoreSystemTypes.Object;
      TypeNodeList parameterTypes = new TypeNodeList(n);
      int m = n;
      for (int i = 0; i < n; i++){
        TypeNode t = this.ParseTypeSignature(sigReader);
        if (t == null)
          m = i--;
        else
          parameterTypes.Add(t);
      }
      FunctionPointer fp = FunctionPointer.For(parameterTypes, returnType);
      fp.CallingConvention = convention;
      fp.VarArgStart = m;
      return fp;
    }
    private StatementList ParseMethodBody(Method/*!*/ method, int methodIndex, int RVA) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      if (method.DeclaringType.Template != null)
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateArguments;
      else
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateParameters;
      BodyParser parser = new BodyParser(this, method, methodIndex, RVA);
      StatementList result = parser.ParseStatements();
      this.currentTypeParameters = savedCurrentTypeParameters;
      return result;
    }
    private InstructionList ParseMethodInstructions(Method/*!*/ method, int methodIndex, int RVA) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      if (method.DeclaringType.Template != null)
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateArguments;
      else
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateParameters;
      InstructionParser parser = new InstructionParser(this, method, methodIndex, RVA);
      InstructionList result = parser.ParseInstructions();
      this.currentTypeParameters = savedCurrentTypeParameters;
      return result;
    }
  }

  internal struct LocalInfo
  {
    public LocalInfo(string name, uint attributes)
    {
      this.Name = name;
      this.Attributes = attributes;
    }
    public readonly string Name;
    public readonly uint Attributes;
  }

  internal abstract class ILParser{
    internal int counter;
    protected Reader/*!*/ reader;
    protected MemoryCursor/*!*/ bodyReader;
    internal int size;
    protected Method/*!*/ method;
    protected int methodIndex;
    protected int RVA;
    protected LocalList/*!*/ locals = new LocalList();

    internal ILParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA) {
      this.reader = reader;
      this.bodyReader = reader.tables.GetNewCursor();
      this.method = method;
#if !FxCop
      this.method.LocalList = this.locals;
#else
      this.method.Locals = this.locals;
#endif
      this.methodIndex = methodIndex;
      this.RVA = RVA;
      //^ base();
    }
    protected Expression Parameters(int i){
      if (this.method.IsStatic) return this.method.Parameters[i];
      if (i == 0) return this.method.ThisParameter;
      return this.method.Parameters[i-1];
    }
    protected void ParseHeader(){
      byte header = this.reader.tables.GetMethodBodyHeaderByte(this.RVA);
      if ((header & 0x3) == 2){
        this.size = header >> 2;
        this.bodyReader = this.reader.tables.GetNewCursor();
        this.reader.tables.Skip(size);
      }else{    
        method.InitLocals = (header & 0x10) != 0;
        byte header2 = this.reader.tables.GetByte();
        int fatHeaderSize = header2 >> 4;
        if (fatHeaderSize == 2) return;
        if (fatHeaderSize != 3) throw new InvalidMetadataException(ExceptionStrings.InvalidFatMethodHeader);
        this.reader.tables.Skip(2); //Skip over maxstack. No need to remember it.
        this.size = this.reader.tables.GetInt32();
        int localIndex = this.reader.tables.GetInt32();
        this.bodyReader = this.reader.tables.GetNewCursor();
        this.reader.tables.Skip(size);
        this.reader.tables.AlignTo32BitBoundary();
        while ((header & 0x8) != 0){
          header = this.reader.tables.GetByte();
          if ((header & 3) != 1) throw new InvalidMetadataException(ExceptionStrings.BadMethodHeaderSection);
          if ((header & 0x80) != 0) throw new InvalidMetadataException(ExceptionStrings.TooManyMethodHeaderSections);
          this.ParseExceptionHandlerEntry((header & 0x40) == 0);
        }
        var localSourceNames = new System.Collections.Generic.Dictionary<int,LocalInfo>();
#if !ROTOR
        if (this.reader.getDebugSymbols && this.reader.debugReader != null){
          ISymUnmanagedMethod methodInfo = null;
          try{
            try{
              this.reader.debugReader.GetMethod(0x6000000|(uint)methodIndex, ref methodInfo);
              if (methodInfo != null){
                ISymUnmanagedScope rootScope = methodInfo.GetRootScope();
                try{
                  this.reader.GetLocalSourceNames(rootScope, localSourceNames);
#if CodeContracts
                  method.ExtraDebugInfo = ExtraPDBInfo.Parse(methodInfo.GetToken(), method, this.reader.debugReader, this.reader);
#endif
                }
                finally{
                  if (rootScope != null)
                    Marshal.ReleaseComObject(rootScope);
                }
              }
            }
            catch (COMException){
            }
            catch (InvalidCastException){
            }
            catch (System.Runtime.InteropServices.InvalidComObjectException){}            
          }
          finally{
            if (methodInfo != null)
              Marshal.ReleaseComObject(methodInfo);
          }
        }
#endif
        this.reader.GetLocals(localIndex, this.locals, localSourceNames);
      }
    }


    abstract protected void ParseExceptionHandlerEntry(bool smallSection);
    protected byte GetByte(){
      this.counter += 1;
      return this.bodyReader.ReadByte();
    }
    protected sbyte GetSByte(){
      this.counter += 1;
      return this.bodyReader.ReadSByte();
    }
    protected short GetInt16(){
      this.counter += 2;
      return this.bodyReader.ReadInt16();
    }
    protected int GetInt32(){
      this.counter += 4;
      return this.bodyReader.ReadInt32();
    }
    protected long GetInt64(){
      this.counter += 8;
      return this.bodyReader.ReadInt64();
    }
    protected float GetSingle(){
      this.counter += 4;
      return this.bodyReader.ReadSingle();
    }
    protected double GetDouble(){
      this.counter += 8;
      return this.bodyReader.ReadDouble();
    }
    protected Member/*!*/ GetMemberFromToken(object memberInfo = null){
      return this.reader.GetMemberFromToken(this.GetInt32(), memberInfo);
    }
    protected Member/*!*/ GetMemberFromToken(out TypeNodeList varArgTypes) {
      return this.reader.GetMemberFromToken(this.GetInt32(), out varArgTypes);
    }
    protected string/*!*/ GetStringFromToken() {
      int tok = this.GetInt32();
      return this.reader.tables.GetUserString(tok & 0xFFFFFF);
    }
    protected OpCode GetOpCode(){
      int result = this.GetByte();
      if (result == (int)OpCode.Prefix1)
        result = result << 8 | this.GetByte();
      return (OpCode)result;
    }
  }
  sealed internal class BodyParser : ILParser{
    private readonly ExpressionStack/*!*/ operandStack = new ExpressionStack();
    private readonly TrivialHashtable/*!*/ blockMap = new TrivialHashtable(32);
    private int alignment = -1;
    private bool isReadOnly;
    private bool isTailCall;
    private bool isVolatile;
    private TypeNode constraint;

    internal BodyParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA)
      : base(reader, method, methodIndex, RVA){
      //^ base;
    }
#if !FxCop
    override protected void ParseExceptionHandlerEntry(bool smallSection){
      int dataSize = this.reader.tables.GetByte();
      int n = (int)(ushort)this.reader.tables.GetInt16();
      if (smallSection)
        n = dataSize / 12;
      else
        n = (dataSize + (n << 8)) / 24;
      if (n < 0) n = 0;
      this.method.ExceptionHandlers = new ExceptionHandlerList(n);
      for (int i = 0; i < n; i++){
        int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset;
        if (smallSection){
          flags = this.reader.tables.GetInt16();
          tryOffset = this.reader.tables.GetUInt16();
          tryLength = this.reader.tables.GetByte();
          handlerOffset = this.reader.tables.GetUInt16();
          handlerLength = this.reader.tables.GetByte();
        }else{
          flags = this.reader.tables.GetInt32();
          tryOffset = this.reader.tables.GetInt32();
          tryLength = this.reader.tables.GetInt32();
          handlerOffset = this.reader.tables.GetInt32();
          handlerLength = this.reader.tables.GetInt32();
        }
        tokenOrOffset = this.reader.tables.GetInt32();
        ExceptionHandler eh = new ExceptionHandler();
        switch(flags){
          case 0x00: 
            eh.HandlerType = NodeType.Catch;
            int pos = this.reader.tables.GetCurrentPosition();
            eh.FilterType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset);
            this.reader.tables.SetCurrentPosition(pos);
            break;
          case 0x01: 
            eh.HandlerType = NodeType.Filter; 
            eh.FilterExpression = Reader.GetOrCreateBlock(blockMap, tokenOrOffset);
            break;
          case 0x02: eh.HandlerType = NodeType.Finally; break;
          case 0x04: eh.HandlerType = NodeType.FaultHandler; break;
          default: throw new InvalidMetadataException(ExceptionStrings.BadExceptionHandlerType);
        }
        eh.TryStartBlock = Reader.GetOrCreateBlock(this.blockMap, tryOffset);
        eh.BlockAfterTryEnd = Reader.GetOrCreateBlock(this.blockMap, tryOffset+tryLength);
        eh.HandlerStartBlock = Reader.GetOrCreateBlock(this.blockMap, handlerOffset);
        eh.BlockAfterHandlerEnd = Reader.GetOrCreateBlock(this.blockMap, handlerOffset+handlerLength);
        this.method.ExceptionHandlers.Add(eh);
      }
    }
#endif
    private AssignmentStatement/*!*/ ParseArrayElementAssignment(OpCode opCode) {
      Expression rhvalue = PopOperand();
      ExpressionList indexers = new ExpressionList(1);
      indexers.Add(PopOperand());
      Expression array = PopOperand();
      Indexer indexer = new Indexer(array, indexers);
      TypeNode t = CoreSystemTypes.Object;
      switch(opCode){
        case OpCode.Stelem_I: t = CoreSystemTypes.IntPtr; break;
        case OpCode.Stelem_I1: t = CoreSystemTypes.Int8; break;
        case OpCode.Stelem_I2: t = CoreSystemTypes.Int16; break;
        case OpCode.Stelem_I4: t = CoreSystemTypes.Int32; break;
        case OpCode.Stelem_I8: t = CoreSystemTypes.Int64; break;
        case OpCode.Stelem_R4: t = CoreSystemTypes.Single; break;
        case OpCode.Stelem_R8: t = CoreSystemTypes.Double; break;
        case OpCode.Stelem: t = (TypeNode)this.GetMemberFromToken(); break;
        default:
          ArrayType arrT = array.Type as ArrayType;
          if (arrT != null) t = arrT.ElementType;
          break;
      }
      indexer.ElementType = indexer.Type = t;
      return new AssignmentStatement(indexer, rhvalue);
    }
    private Indexer/*!*/ ParseArrayElementLoad(OpCode opCode, TypeNode elementType){
      ExpressionList indexers = new ExpressionList(1); indexers.Add(PopOperand());
      Expression array = PopOperand();
      Indexer indexer = new Indexer(array, indexers);
      TypeNode t = elementType;
      switch(opCode){
        case OpCode.Ldelem_I1: t = CoreSystemTypes.Int8; break;
        case OpCode.Ldelem_U1: t = CoreSystemTypes.UInt8; break;
        case OpCode.Ldelem_I2: t = CoreSystemTypes.Int16; break;
        case OpCode.Ldelem_U2: t = CoreSystemTypes.UInt16; break;
        case OpCode.Ldelem_I4: t = CoreSystemTypes.Int32; break;
        case OpCode.Ldelem_U4: t = CoreSystemTypes.UInt32; break;
        case OpCode.Ldelem_I8: t = CoreSystemTypes.Int64; break;
        case OpCode.Ldelem_I: t = CoreSystemTypes.IntPtr; break;
        case OpCode.Ldelem_R4: t = CoreSystemTypes.Single; break;
        case OpCode.Ldelem_R8: t = CoreSystemTypes.Double; break;
        case OpCode.Ldelem: t = (TypeNode)this.GetMemberFromToken(); break;
        default:
          if (t != null) break;
          t = CoreSystemTypes.Object;
          ArrayType arrT = array.Type as ArrayType;
          if (arrT != null) t = arrT.ElementType;
          break;
      }
      indexer.ElementType = indexer.Type = t;
      return indexer;
    }
    private UnaryExpression/*!*/ ParseArrayElementLoadAddress() {
      TypeNode elemType = (TypeNode)this.GetMemberFromToken();
      return new UnaryExpression(this.ParseArrayElementLoad(0, elemType), this.isReadOnly ? NodeType.ReadOnlyAddressOf : NodeType.AddressOf, elemType.GetReferenceType());
    }
    private static UnaryExpression/*!*/ SetType(UnaryExpression/*!*/ uex) {
      if (uex == null || uex.Operand == null) return uex;
      TypeNode elemType = uex.Operand.Type;
      if (elemType == null) return uex;
      uex.Type = elemType.GetReferenceType();
      return uex;
    }
    private BinaryExpression/*!*/ ParseBinaryComparison(NodeType oper) {
      Expression op2 = PopOperand();
      Expression op1 = PopOperand();
      BinaryExpression result = new BinaryExpression(op1, op2, oper);
      result.Type = CoreSystemTypes.Int32;
      return result;
    }
    private BinaryExpression/*!*/ ParseBinaryOperation(NodeType oper) {
      Expression op2 = PopOperand();
      Expression op1 = PopOperand();
      BinaryExpression result = new BinaryExpression(op1, op2, oper);
      result.Type = op1.Type;
      if (result.Type == null) result.Type = op2.Type;
      return result;
    }
    private UnaryExpression/*!*/ ParseUnaryOperation(NodeType oper) {
      Expression op = PopOperand();
      return new UnaryExpression(op, oper, op.Type);
    }
    private Branch/*!*/ ParseBranch(NodeType operatorType, int operandCount, bool shortOffset, bool unordered) {
      return this.ParseBranch(operatorType, operandCount, shortOffset, unordered, false);
    }
    private Branch/*!*/ ParseBranch(NodeType operatorType, int operandCount, bool shortOffset, bool unordered, bool leavesExceptionBlock) {
      Expression operand2 = operandCount > 1 ? PopOperand() : null;
      Expression operand1 = operandCount > 0 ? PopOperand() : null;
      Expression condition = operandCount > 1 ? (Expression)new BinaryExpression(operand1, operand2, operatorType) :
        (operandCount > 0 ? (operatorType == NodeType.Nop ? operand1 : (Expression)new UnaryExpression(operand1, operatorType)) : null);
      int targetAddress = shortOffset ? this.GetSByte() : this.GetInt32();
      Block targetBlock = (Block)this.blockMap[targetAddress+this.counter+1];
      Debug.Assert(targetBlock != null);
      if (targetAddress >= 0 && !this.reader.preserveShortBranches) shortOffset = false;
      return new Branch(condition, targetBlock, shortOffset, unordered, leavesExceptionBlock);
    }
    private MethodCall/*!*/ ParseCall(NodeType typeOfCall, out bool isStatement) {
      TypeNodeList varArgTypes;
      Method meth = (Method)this.GetMemberFromToken(out varArgTypes);
      int numVarArgs = varArgTypes == null ? 0 : varArgTypes.Count;
      isStatement = BodyParser.TypeIsVoid(meth.ReturnType);
      int n = meth.Parameters == null ? 0 : meth.Parameters.Count; 
      if (typeOfCall == NodeType.Jmp) n = 0;
      else n += numVarArgs;
      Expression[] args = new Expression[n];
      ExpressionList arguments = new ExpressionList(n);
      for (int i = n-1; i >= 0; i--) args[i] = PopOperand();
      for (int i = 0; i < n; i++) arguments.Add(args[i]);
      if (varArgTypes != null) {
        for (int i = n-1, j = numVarArgs; j > 0; j--, i--) {
          Expression e = arguments[i];
          TypeNode t = varArgTypes[j-1];
          if (e != null && t != null) e.Type = t;
        }
      }
      Expression thisob = meth.IsStatic ? null : PopOperand();
      MemberBinding methBinding = new MemberBinding(thisob, meth);
      MethodCall result = new MethodCall(methBinding, arguments, typeOfCall);
      result.Type = meth.ReturnType;
      result.IsTailCall = this.isTailCall;
      if (this.constraint != null){
        result.Constraint = this.constraint;
        this.constraint = null;
      }
      return result;
    }
    private static bool TypeIsVoid(TypeNode t){
      if (t == null) return false;
      for(;;){
        switch(t.NodeType){
          case NodeType.OptionalModifier:
          case NodeType.RequiredModifier:
            t = ((TypeModifier)t).ModifiedType;
            break;
          default:
            return t == CoreSystemTypes.Void;
        }
      }
    }
    private MethodCall/*!*/ ParseCalli(out bool isStatement) {
      FunctionPointer fp = this.reader.GetCalliSignature(this.GetInt32());
      if (fp == null) throw new InvalidMetadataException(ExceptionStrings.BaddCalliSignature);
      isStatement = BodyParser.TypeIsVoid(fp.ReturnType);
      int n = fp.ParameterTypes.Count; 
      Expression[] args = new Expression[n+1];
      ExpressionList arguments = new ExpressionList(n+1);
      for (int i = n; i >= 0; i--) args[i] = PopOperand();
      for (int i = 0; i <= n; i++) arguments.Add(args[i]);
      Expression thisob = fp.IsStatic ? null : PopOperand();
      MemberBinding methBinding = new MemberBinding(thisob, fp);
      MethodCall result = new MethodCall(methBinding, arguments, NodeType.Calli);
      result.Type = fp.ReturnType;
      result.IsTailCall = this.isTailCall;
      return result;
    }
    private static Expression/*!*/ ParseTypeCheck(Expression operand, TypeNode type, NodeType typeOfCheck) {
      TypeNode etype = type;
      if (typeOfCheck == NodeType.Unbox) etype = type.GetReferenceType();
      Expression expr = new BinaryExpression(operand, new Literal(type, CoreSystemTypes.Type), typeOfCheck, etype);
      return expr;
    }
    private Construct/*!*/ ParseConstruct() {
      TypeNodeList varArgTypes;
      Method meth = (Method)this.GetMemberFromToken(out varArgTypes);
      int n = meth.Parameters.Count;
      Expression[] args = new Expression[n];
      ExpressionList arguments = new ExpressionList(n);
      for (int i = n-1; i >= 0; i--) args[i] = PopOperand();
      for (int i = 0; i < n; i++) arguments.Add(args[i]);
      Construct result = new Construct(new MemberBinding(null, meth), arguments);
      result.Type = meth.DeclaringType;
      return result;
    }
    private AssignmentStatement/*!*/ ParseCopyObject() {
      TypeNode type = (TypeNode)this.GetMemberFromToken();
      Expression rhaddr = PopOperand();
      Expression lhaddr = PopOperand();
      return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), new AddressDereference(rhaddr, type));
    }
    private UnaryExpression /*!*/ ParseLoadRuntimeMetadataToken() {
      Expression expr = null;
      TypeNode exprType = null;
      Member member = this.GetMemberFromToken();
      TypeNode t = member as TypeNode;
      if (t == null) {
        exprType = (member.NodeType == NodeType.Field)
          ? CoreSystemTypes.RuntimeFieldHandle : CoreSystemTypes.RuntimeMethodHandle;
        expr = new MemberBinding(null, member);
      } else {
        exprType = CoreSystemTypes.RuntimeTypeHandle;
        expr = new Literal(t, CoreSystemTypes.Type);
      }
      return new UnaryExpression(expr, NodeType.Ldtoken, exprType);
    }
    private AssignmentStatement/*!*/ ParseInitObject() {
      TypeNode type = (TypeNode)this.GetMemberFromToken();
      Expression lhaddr = PopOperand();
      return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), new Literal(null, CoreSystemTypes.Object));
    }
    private ConstructArray/*!*/ ParseNewArray() {
      TypeNode type = (TypeNode)this.GetMemberFromToken();
      ExpressionList sizes = new ExpressionList(1);
      sizes.Add(PopOperand());
      ConstructArray result = new ConstructArray(type, sizes, null);
      result.Type = type.GetArrayType(1);
      return result;
    }
#if !FxCop
    internal StatementList/*!*/ ParseStatements() {
      this.ParseHeader();
      if (this.size == 0) return new StatementList(0);
      this.CreateBlocksForBranchTargets();
      StatementList result = new StatementList();
      Block currentBlock = null;
      while (this.counter < size){
        if (currentBlock == null){
          currentBlock = Reader.GetOrCreateBlock(this.blockMap, this.counter);
#if ILOFFSETS
          currentBlock.SourceContext = lastSourceContext;
#endif
          result.Add(currentBlock);
        }
        bool endOfBasicBlock = this.ParseStatement(currentBlock);
        if (endOfBasicBlock) currentBlock = null;
      }
      result.Add(Reader.GetOrCreateBlock(this.blockMap, this.counter));
      return result;
    }
#endif
    private bool ParseStatement(Block/*!*/ block) {
      //parse instructions and put in expression tree until an assignment, void call, branch target, or branch is encountered
      StatementList statementList = block.Statements;
      Expression expr = null;
      Statement statement = null;
      bool transferStatement = false;
      int startingAddress = 0;
#if !FxCop
      SourceContext sourceContext = new SourceContext();
#if !CodeContracts
      sourceContext.StartPos = this.counter;
#endif
#endif
#if !ROTOR
      if (this.method.contextForOffset != null){
        object sctx = this.method.contextForOffset[this.counter+1];
        if (sctx != null) sourceContext = (SourceContext)sctx;
#if ILOFFSETS
        else
        {
          sourceContext = this.lastSourceContext;
        }
#endif
      }
#endif
      while (true){
        bool isStatement = false;
        startingAddress = this.counter+1; //Add one so that it is never zero (the latter means no entry to the TrivialHashtable)
#if FxCop || ILOFFSETS
        this.ilOffset = this.counter;
        this.opCode = this.GetOpCode();
#else
        OpCode opCode = this.GetOpCode();
#endif
#if FxCop
        if (this.handlerMap.TryGetValue(this.ilOffset, out expr)){
          expr.sourceContext = sourceContext;
          expr.ILOffset = this.ilOffset;
          this.operandStack.Push(expr);
        }
#endif
        switch (opCode){
          case OpCode.Nop: statement = new Statement(NodeType.Nop); goto done;
          case OpCode.Break: statement = new Statement(NodeType.DebugBreak); goto done;
          case OpCode.Ldarg_0: expr = this.Parameters(0); break;
          case OpCode.Ldarg_1: expr = this.Parameters(1); break;
          case OpCode.Ldarg_2: expr = this.Parameters(2); break;
          case OpCode.Ldarg_3: expr = this.Parameters(3); break;
          case OpCode.Ldloc_0: expr = this.locals[0]; break;
          case OpCode.Ldloc_1: expr = this.locals[1]; break;
          case OpCode.Ldloc_2: expr = this.locals[2]; break;
          case OpCode.Ldloc_3: expr = this.locals[3]; break;
          case OpCode.Stloc_0: statement = new AssignmentStatement(this.locals[0], PopOperand()); goto done;
          case OpCode.Stloc_1: statement = new AssignmentStatement(this.locals[1], PopOperand()); goto done;
          case OpCode.Stloc_2: statement = new AssignmentStatement(this.locals[2], PopOperand()); goto done;
          case OpCode.Stloc_3: statement = new AssignmentStatement(this.locals[3], PopOperand()); goto done;
          case OpCode.Ldarg_S: expr = this.Parameters(this.GetByte()); break;
          case OpCode.Ldarga_S: expr = SetType(new UnaryExpression(this.Parameters(this.GetByte()), NodeType.AddressOf)); break;
          case OpCode.Starg_S: statement = new AssignmentStatement(this.Parameters(this.GetByte()), PopOperand()); goto done;
          case OpCode.Ldloc_S: expr = this.locals[this.GetByte()]; break;
          case OpCode.Ldloca_S: expr = SetType(new UnaryExpression(this.locals[this.GetByte()], NodeType.AddressOf)); break;
          case OpCode.Stloc_S: statement = new AssignmentStatement(this.locals[this.GetByte()], PopOperand()); goto done;
#if true || CodeContracts
          case OpCode.Ldnull: expr = Literal.Null; break;
          case OpCode.Ldc_I4_M1: expr = Literal.Int32MinusOne; break;
          case OpCode.Ldc_I4_0: expr = Literal.Int32Zero; break;
          case OpCode.Ldc_I4_1: expr = Literal.Int32One; break;
          case OpCode.Ldc_I4_2: expr = Literal.Int32Two; break;
#else
          case OpCode.Ldnull: expr = new Literal(null, CoreSystemTypes.Object); break;
          case OpCode.Ldc_I4_M1: expr = new Literal(-1, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_0: expr = new Literal(0, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_1: expr = new Literal(1, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_2: expr = new Literal(2, CoreSystemTypes.Int32); break;
#endif
          case OpCode.Ldc_I4_3: expr = new Literal(3, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_4: expr = new Literal(4, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_5: expr = new Literal(5, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_6: expr = new Literal(6, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_7: expr = new Literal(7, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_8: expr = new Literal(8, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_S: expr = new Literal((int)this.GetSByte(), CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4: expr = new Literal(this.GetInt32(), CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I8: expr = new Literal(this.GetInt64(), CoreSystemTypes.Int64); break;
          case OpCode.Ldc_R4: expr = new Literal(this.GetSingle(), CoreSystemTypes.Single); break;
          case OpCode.Ldc_R8: expr = new Literal(this.GetDouble(), CoreSystemTypes.Double); break;
          case OpCode.Dup: statement = new ExpressionStatement(new Expression(NodeType.Dup)); goto done;
          case OpCode.Pop: statement = new ExpressionStatement(new UnaryExpression(PopOperand(), NodeType.Pop)); goto done;
          case OpCode.Jmp: expr = this.ParseCall(NodeType.Jmp, out isStatement); if (isStatement) goto done; break;
          case OpCode.Call: expr = this.ParseCall(NodeType.Call, out isStatement); if (isStatement) goto done; break;
          case OpCode.Calli: expr = this.ParseCalli(out isStatement); if (isStatement) goto done; break;
          case OpCode.Ret:
            Expression retVal = BodyParser.TypeIsVoid(this.method.ReturnType) ? null : PopOperand();
            statement = new Return(retVal); 
            transferStatement = true; goto done;
          case OpCode.Br_S: statement = this.ParseBranch(NodeType.Nop, 0, true, false); transferStatement = true; goto done;
          case OpCode.Brfalse_S: statement = this.ParseBranch(NodeType.LogicalNot, 1, true, false); transferStatement = true; goto done;
          case OpCode.Brtrue_S: statement = this.ParseBranch(NodeType.Nop, 1, true, false); transferStatement = true; goto done;
          case OpCode.Beq_S: statement = this.ParseBranch(NodeType.Eq, 2, true, false); transferStatement = true; goto done;
          case OpCode.Bge_S: statement = this.ParseBranch(NodeType.Ge, 2, true, false); transferStatement = true; goto done;
          case OpCode.Bgt_S: statement = this.ParseBranch(NodeType.Gt, 2, true, false); transferStatement = true; goto done;
          case OpCode.Ble_S: statement = this.ParseBranch(NodeType.Le, 2, true, false); transferStatement = true; goto done;
          case OpCode.Blt_S: statement = this.ParseBranch(NodeType.Lt, 2, true, false); transferStatement = true; goto done;
          case OpCode.Bne_Un_S: statement = this.ParseBranch(NodeType.Ne, 2, true, true); transferStatement = true; goto done;
          case OpCode.Bge_Un_S: statement = this.ParseBranch(NodeType.Ge, 2, true, true); transferStatement = true; goto done;
          case OpCode.Bgt_Un_S: statement = this.ParseBranch(NodeType.Gt, 2, true, true); transferStatement = true; goto done;
          case OpCode.Ble_Un_S: statement = this.ParseBranch(NodeType.Le, 2, true, true); transferStatement = true; goto done;
          case OpCode.Blt_Un_S: statement = this.ParseBranch(NodeType.Lt, 2, true, true); transferStatement = true; goto done;
          case OpCode.Br: statement = this.ParseBranch(NodeType.Nop, 0, false, false); transferStatement = true; goto done;
          case OpCode.Brfalse: statement = this.ParseBranch(NodeType.LogicalNot, 1, false, false); transferStatement = true; goto done;
          case OpCode.Brtrue: statement = this.ParseBranch(NodeType.Nop, 1, false, false); transferStatement = true; goto done;
          case OpCode.Beq: statement = this.ParseBranch(NodeType.Eq, 2, false, false); transferStatement = true; goto done;
          case OpCode.Bge: statement = this.ParseBranch(NodeType.Ge, 2, false, false); transferStatement = true; goto done;
          case OpCode.Bgt: statement = this.ParseBranch(NodeType.Gt, 2, false, false); transferStatement = true; goto done;
          case OpCode.Ble: statement = this.ParseBranch(NodeType.Le, 2, false, false); transferStatement = true; goto done;
          case OpCode.Blt: statement = this.ParseBranch(NodeType.Lt, 2, false, false); transferStatement = true; goto done;
          case OpCode.Bne_Un: statement = this.ParseBranch(NodeType.Ne, 2, false, true); transferStatement = true; goto done;
          case OpCode.Bge_Un: statement = this.ParseBranch(NodeType.Ge, 2, false, true); transferStatement = true; goto done;
          case OpCode.Bgt_Un: statement = this.ParseBranch(NodeType.Gt, 2, false, true); transferStatement = true; goto done;
          case OpCode.Ble_Un: statement = this.ParseBranch(NodeType.Le, 2, false, true); transferStatement = true; goto done;
          case OpCode.Blt_Un: statement = this.ParseBranch(NodeType.Lt, 2, false, true); transferStatement = true; goto done;
          case OpCode.Switch: statement = this.ParseSwitchInstruction(); transferStatement = true; goto done;
          case OpCode.Ldind_I1: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int8, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_U1: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt8, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I2: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int16, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_U2: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt16, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int32, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_U4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt32, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I8: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int64, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I: expr = new AddressDereference(PopOperand(), CoreSystemTypes.IntPtr, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_R4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Single, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_R8: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Double, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_Ref: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Object, this.isVolatile, this.alignment); break;
          case OpCode.Stind_Ref: statement = this.ParseStoreIndirect(CoreSystemTypes.Object); goto done;
          case OpCode.Stind_I1: statement = this.ParseStoreIndirect(CoreSystemTypes.Int8); goto done;
          case OpCode.Stind_I2: statement = this.ParseStoreIndirect(CoreSystemTypes.Int16); goto done;
          case OpCode.Stind_I4: statement = this.ParseStoreIndirect(CoreSystemTypes.Int32); goto done;
          case OpCode.Stind_I8: statement = this.ParseStoreIndirect(CoreSystemTypes.Int64); goto done;
          case OpCode.Stind_R4: statement = this.ParseStoreIndirect(CoreSystemTypes.Single); goto done;
          case OpCode.Stind_R8: statement = this.ParseStoreIndirect(CoreSystemTypes.Double); goto done;
          case OpCode.Add: expr = this.ParseBinaryOperation(NodeType.Add); break;
          case OpCode.Sub: expr = this.ParseBinaryOperation(NodeType.Sub); break;
          case OpCode.Mul: expr = this.ParseBinaryOperation(NodeType.Mul); break;
          case OpCode.Div: expr = this.ParseBinaryOperation(NodeType.Div); break;
          case OpCode.Div_Un: expr = this.ParseBinaryOperation(NodeType.Div_Un); break;
          case OpCode.Rem: expr = this.ParseBinaryOperation(NodeType.Rem); break;
          case OpCode.Rem_Un: expr = this.ParseBinaryOperation(NodeType.Rem_Un); break;
          case OpCode.And: expr = this.ParseBinaryOperation(NodeType.And); break;
          case OpCode.Or: expr = this.ParseBinaryOperation(NodeType.Or); break;
          case OpCode.Xor: expr = this.ParseBinaryOperation(NodeType.Xor); break;
          case OpCode.Shl: expr = this.ParseBinaryOperation(NodeType.Shl); break;
          case OpCode.Shr: expr = this.ParseBinaryOperation(NodeType.Shr); break;
          case OpCode.Shr_Un: expr = this.ParseBinaryOperation(NodeType.Shr_Un); break;
          case OpCode.Neg: expr = this.ParseUnaryOperation(NodeType.Neg); break;
          case OpCode.Not: expr = this.ParseUnaryOperation(NodeType.Not); break;
          case OpCode.Conv_I1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I1, CoreSystemTypes.Int8); break;
          case OpCode.Conv_I2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I2, CoreSystemTypes.Int16); break;
          case OpCode.Conv_I4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I4, CoreSystemTypes.Int32); break;
          case OpCode.Conv_I8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I8, CoreSystemTypes.Int64); break;
          case OpCode.Conv_R4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R4, CoreSystemTypes.Single); break;
          case OpCode.Conv_R8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R8, CoreSystemTypes.Double); break;
          case OpCode.Conv_U4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U4, CoreSystemTypes.UInt32); break;
          case OpCode.Conv_U8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U8, CoreSystemTypes.UInt64); break;
          case OpCode.Callvirt: expr = this.ParseCall(NodeType.Callvirt, out isStatement); if (isStatement) goto done; break;
          case OpCode.Cpobj: statement = this.ParseCopyObject(); goto done;
          case OpCode.Ldobj: expr = new AddressDereference(PopOperand(), (TypeNode)this.GetMemberFromToken(), this.isVolatile, this.alignment); break;
          case OpCode.Ldstr: expr = new Literal(this.GetStringFromToken(), CoreSystemTypes.String); break;
          case OpCode.Newobj: expr = this.ParseConstruct(); break;
          case OpCode.Castclass: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Castclass); break;
          case OpCode.Isinst: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Isinst); break;
          case OpCode.Conv_R_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R_Un, CoreSystemTypes.Double); break;
          case OpCode.Unbox: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Unbox); break;
          case OpCode.Throw: statement = new Throw(PopOperand()); transferStatement = true; goto done;
          case OpCode.Ldfld: 
            expr = new MemberBinding(PopOperand(), this.GetMemberFromToken(), this.isVolatile, this.alignment);
            break;
          case OpCode.Ldflda: 
            expr = SetType(new UnaryExpression(new MemberBinding(PopOperand(), this.GetMemberFromToken(), this.isVolatile, this.alignment), NodeType.AddressOf)); 
            break;
          case OpCode.Stfld: statement = this.ParseStoreField(); goto done;
          case OpCode.Ldsfld: expr = new MemberBinding(null, this.GetMemberFromToken(new FieldInfo { IsStatic = true }), this.isVolatile, this.alignment); break;
          case OpCode.Ldsflda: expr = SetType(new UnaryExpression(new MemberBinding(null, this.GetMemberFromToken(new FieldInfo { IsStatic = true }), this.isVolatile, this.alignment), NodeType.AddressOf)); break;
          case OpCode.Stsfld: statement = new AssignmentStatement(new MemberBinding(null, this.GetMemberFromToken(), this.isVolatile, this.alignment), PopOperand()); goto done;
          case OpCode.Stobj: statement = this.ParseStoreIndirect((TypeNode)this.GetMemberFromToken()); goto done;
          case OpCode.Conv_Ovf_I1_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I1_Un, CoreSystemTypes.Int8); break;
          case OpCode.Conv_Ovf_I2_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I2_Un, CoreSystemTypes.Int16); break;
          case OpCode.Conv_Ovf_I4_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I4_Un, CoreSystemTypes.Int32); break;
          case OpCode.Conv_Ovf_I8_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I8_Un, CoreSystemTypes.Int64); break;
          case OpCode.Conv_Ovf_U1_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U1_Un, CoreSystemTypes.UInt8); break;
          case OpCode.Conv_Ovf_U2_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U2_Un, CoreSystemTypes.UInt16); break;
          case OpCode.Conv_Ovf_U4_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U4_Un, CoreSystemTypes.UInt32); break;
          case OpCode.Conv_Ovf_U8_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U8_Un, CoreSystemTypes.UInt64); break;
          case OpCode.Conv_Ovf_I_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I_Un, CoreSystemTypes.IntPtr); break;
          case OpCode.Conv_Ovf_U_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U_Un, CoreSystemTypes.UIntPtr); break;
          case OpCode.Box: 
            TypeNode t = (TypeNode)this.GetMemberFromToken();
            TypeNode bt = t is EnumNode ? CoreSystemTypes.Enum : CoreSystemTypes.ValueType;
            expr = new BinaryExpression(PopOperand(), new Literal(t, CoreSystemTypes.Type), NodeType.Box, bt); break;
          case OpCode.Newarr: expr = this.ParseNewArray(); break;
          case OpCode.Ldlen: expr = new UnaryExpression(PopOperand(), NodeType.Ldlen, CoreSystemTypes.UIntPtr); break;
          case OpCode.Ldelema: expr = this.ParseArrayElementLoadAddress(); break;
          case OpCode.Ldelem_I1: 
          case OpCode.Ldelem_U1: 
          case OpCode.Ldelem_I2: 
          case OpCode.Ldelem_U2: 
          case OpCode.Ldelem_I4: 
          case OpCode.Ldelem_U4: 
          case OpCode.Ldelem_I8: 
          case OpCode.Ldelem_I: 
          case OpCode.Ldelem_R4: 
          case OpCode.Ldelem_R8: 
          case OpCode.Ldelem_Ref: expr = this.ParseArrayElementLoad(opCode, null); break;
          case OpCode.Stelem_I:
          case OpCode.Stelem_I1:
          case OpCode.Stelem_I2:
          case OpCode.Stelem_I4:
          case OpCode.Stelem_I8:
          case OpCode.Stelem_R4:
          case OpCode.Stelem_R8:
          case OpCode.Stelem_Ref: statement = this.ParseArrayElementAssignment(opCode); goto done;
          case OpCode.Ldelem: expr = this.ParseArrayElementLoad(opCode, null); break;
          case OpCode.Stelem: statement = this.ParseArrayElementAssignment(opCode); goto done;
          case OpCode.Unbox_Any: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.UnboxAny); break;
          case OpCode.Conv_Ovf_I1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I1, CoreSystemTypes.Int8); break;
          case OpCode.Conv_Ovf_U1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U1, CoreSystemTypes.UInt8); break;
          case OpCode.Conv_Ovf_I2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I2, CoreSystemTypes.Int16); break;
          case OpCode.Conv_Ovf_U2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U2, CoreSystemTypes.UInt16); break;
          case OpCode.Conv_Ovf_I4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I4, CoreSystemTypes.Int32); break;
          case OpCode.Conv_Ovf_U4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U4, CoreSystemTypes.UInt32); break;
          case OpCode.Conv_Ovf_I8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I8, CoreSystemTypes.Int64); break;
          case OpCode.Conv_Ovf_U8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U8, CoreSystemTypes.UInt64); break;
          case OpCode.Refanyval: expr = new BinaryExpression(PopOperand(), new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Refanyval, CoreSystemTypes.IntPtr); break;
          case OpCode.Ckfinite: expr = this.ParseUnaryOperation(NodeType.Ckfinite); break;
          case OpCode.Mkrefany: expr = new BinaryExpression(PopOperand(), new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Mkrefany, CoreSystemTypes.DynamicallyTypedReference); break;
          case OpCode.Ldtoken: expr = ParseLoadRuntimeMetadataToken(); break;
          case OpCode.Conv_U2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U2, CoreSystemTypes.UInt16); break;
          case OpCode.Conv_U1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U1, CoreSystemTypes.UInt8); break;
          case OpCode.Conv_I: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I, CoreSystemTypes.IntPtr); break;
          case OpCode.Conv_Ovf_I: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I, CoreSystemTypes.IntPtr); break;
          case OpCode.Conv_Ovf_U: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U, CoreSystemTypes.UIntPtr); break;
          case OpCode.Add_Ovf: expr = this.ParseBinaryOperation(NodeType.Add_Ovf); break;
          case OpCode.Add_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Add_Ovf_Un); break;
          case OpCode.Mul_Ovf: expr = this.ParseBinaryOperation(NodeType.Mul_Ovf); break;
          case OpCode.Mul_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Mul_Ovf_Un); break;
          case OpCode.Sub_Ovf: expr = this.ParseBinaryOperation(NodeType.Sub_Ovf); break;
          case OpCode.Sub_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Sub_Ovf_Un); break;
          case OpCode.Endfinally: statement = new EndFinally(); transferStatement = true; goto done;
          case OpCode.Leave: statement = this.ParseBranch(NodeType.Nop, 0, false, false, true); transferStatement = true; goto done;
          case OpCode.Leave_S: statement = this.ParseBranch(NodeType.Nop, 0, true, false, true); transferStatement = true; goto done;
          case OpCode.Stind_I: statement = this.ParseStoreIndirect(CoreSystemTypes.IntPtr); goto done;
          case OpCode.Conv_U: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U, CoreSystemTypes.UIntPtr); break;
          case OpCode.Arglist: expr = new Expression(NodeType.Arglist, CoreSystemTypes.ArgIterator); break;
          case OpCode.Ceq: expr = this.ParseBinaryComparison(NodeType.Ceq); break;
          case OpCode.Cgt: expr = this.ParseBinaryComparison(NodeType.Cgt); break;
          case OpCode.Cgt_Un: expr = this.ParseBinaryComparison(NodeType.Cgt_Un); break;
          case OpCode.Clt: expr = this.ParseBinaryComparison(NodeType.Clt); break;
          case OpCode.Clt_Un: expr = this.ParseBinaryComparison(NodeType.Clt_Un); break;
          case OpCode.Ldftn: expr = new UnaryExpression(new MemberBinding(null, this.GetMemberFromToken()), NodeType.Ldftn, CoreSystemTypes.IntPtr); break;
          case OpCode.Ldvirtftn: expr = new BinaryExpression(PopOperand(), new MemberBinding(null, this.GetMemberFromToken()), NodeType.Ldvirtftn, CoreSystemTypes.IntPtr); break;
          case OpCode.Ldarg: expr = this.Parameters((ushort)this.GetInt16()); break;
          case OpCode.Ldarga: expr = SetType(new UnaryExpression(this.Parameters((ushort)this.GetInt16()), NodeType.AddressOf)); break;
          case OpCode.Starg: statement = new AssignmentStatement(this.Parameters((ushort)this.GetInt16()), PopOperand()); goto done;
          case OpCode.Ldloc: expr = this.locals[(ushort)this.GetInt16()]; break;
          case OpCode.Ldloca: expr = SetType(new UnaryExpression(this.locals[(ushort)this.GetInt16()], NodeType.AddressOf)); break;
          case OpCode.Stloc: statement = new AssignmentStatement(this.locals[(ushort)this.GetInt16()], PopOperand()); goto done;
          case OpCode.Localloc: expr = new UnaryExpression(PopOperand(), NodeType.Localloc, CoreSystemTypes.Void); break;
          case OpCode.Endfilter: statement = new EndFilter(PopOperand()); transferStatement = true; goto done;
          case OpCode.Unaligned_: this.alignment = this.GetByte(); continue;
          case OpCode.Volatile_: this.isVolatile = true; continue;
          case OpCode.Tail_: this.isTailCall = true; continue;
          case OpCode.Initobj: statement = this.ParseInitObject(); goto done;
          case OpCode.Constrained_: this.constraint = this.GetMemberFromToken() as TypeNode; continue;
          case OpCode.Cpblk: expr = this.ParseTernaryOperation(NodeType.Cpblk); goto done;
          case OpCode.Initblk: expr = this.ParseTernaryOperation(NodeType.Initblk); goto done;
          case OpCode.Rethrow: statement = new Throw(null); statement.NodeType = NodeType.Rethrow; transferStatement = true; goto done;
          case OpCode.Sizeof: expr = new UnaryExpression(new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Sizeof, CoreSystemTypes.Int32); break;
          case OpCode.Refanytype: expr = new UnaryExpression(PopOperand(), NodeType.Refanytype, CoreSystemTypes.RuntimeTypeHandle); break;
          case OpCode.Readonly_: this.isReadOnly = true; continue;
          default: throw new InvalidMetadataException(ExceptionStrings.UnknownOpCode);
        }
        if (this.blockMap[this.counter+1] != null){
          transferStatement = true; //Falls through to the next basic block, so implicitly a "transfer" statement
          goto done;
        }
        //^ assume expr != null;
#if FxCop
        expr.sourceContext = sourceContext;
#endif
#if FxCop || ILOFFSETS
        expr.ILOffset = this.ilOffset;
#endif
        this.operandStack.Push(expr);
        this.isReadOnly = false;
        this.isVolatile = false;
        this.isTailCall = false;        
        this.alignment = -1;
      }
    done:
      for (int i = 0; i <= this.operandStack.top; i++){
        Expression e = this.operandStack.elements[i];
        //^ assume e != null;
        Statement s = new ExpressionStatement(e);
#if FxCop
        s.SourceContext = this.sourceContext;
        s.ILOffset = this.ilOffset;
#endif
#if ILOFFSETS
        s.ILOffset = this.ilOffset;
        s.SourceContext = sourceContext;
#endif
        statementList.Add(s);
      }
      this.operandStack.top = -1;
      if (statement == null) {
        statement = new ExpressionStatement(expr);
#if FxCop
        expr.sourceContext = this.sourceContext;
#endif
#if FxCop || ILOFFSETS
        expr.ILOffset = this.ilOffset;
#endif
      }
      statement.SourceContext = sourceContext;
#if FxCop || ILOFFSETS
      statement.ILOffset = this.ilOffset;
#endif
#if ILOFFSETS
      this.lastSourceContext = sourceContext;
#endif
      statementList.Add(statement);
      if (transferStatement) return true;
      return this.blockMap[this.counter+1] != null;
    }
    private AssignmentStatement ParseStoreField(){
      Expression rhvalue = PopOperand();
      Expression thisob = PopOperand();
      AssignmentStatement s = new AssignmentStatement(new MemberBinding(thisob, this.GetMemberFromToken(), this.isVolatile, this.alignment), rhvalue);
      return s;
    }
    private AssignmentStatement ParseStoreIndirect(TypeNode type){
      Expression rhvalue = PopOperand();
      Expression lhaddr = PopOperand();
      return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), rhvalue);
    }
    private SwitchInstruction ParseSwitchInstruction(){
      int numTargets = this.GetInt32();
      int offset = this.counter + numTargets*4;
      BlockList targetList = new BlockList(numTargets);
      for (int i = 0; i < numTargets; i++){
        int targetAddress = this.GetInt32() + offset;
        targetList.Add(Reader.GetOrCreateBlock(this.blockMap, targetAddress));
      }
      return new SwitchInstruction(PopOperand(), targetList);
    }
    private TernaryExpression ParseTernaryOperation(NodeType oper){
      Expression op3 = PopOperand();
      Expression op2 = PopOperand();
      Expression op1 = PopOperand();
      return new TernaryExpression(op1, op2, op3, oper, null);
    }
    private void CreateBlocksForBranchTargets(){
      int savedPosition = bodyReader.Position;
      while (this.counter < this.size)
        this.ProcessOneILInstruction();
      this.counter = 0;
      bodyReader.Position = savedPosition;
    }
    private void ProcessOneILInstruction(){
      OpCode opc = this.GetOpCode();
      switch(opc){
        case OpCode.Ldarg_S:
        case OpCode.Ldarga_S:
        case OpCode.Starg_S:
        case OpCode.Ldloc_S:
        case OpCode.Ldloca_S:
        case OpCode.Stloc_S:
        case OpCode.Ldc_I4_S:
          this.GetByte(); return;
        case OpCode.Ldc_I4:
        case OpCode.Jmp:
        case OpCode.Call:
        case OpCode.Calli:
        case OpCode.Callvirt:
        case OpCode.Cpobj:
        case OpCode.Ldobj:
        case OpCode.Ldstr:
        case OpCode.Newobj:
        case OpCode.Castclass:
        case OpCode.Isinst:
        case OpCode.Unbox:
        case OpCode.Ldfld:
        case OpCode.Ldflda:
        case OpCode.Stfld:
        case OpCode.Ldsfld:
        case OpCode.Ldsflda:
        case OpCode.Stsfld:
        case OpCode.Stobj:
        case OpCode.Box:
        case OpCode.Newarr:
        case OpCode.Ldelema:
        case OpCode.Ldelem:
        case OpCode.Stelem:
        case OpCode.Unbox_Any:
        case OpCode.Refanyval:
        case OpCode.Mkrefany: 
        case OpCode.Ldtoken:
          this.GetInt32(); return;
        case OpCode.Ldc_I8:
          this.GetInt64(); return;
        case OpCode.Ldc_R4: 
          this.GetSingle(); return;
        case OpCode.Ldc_R8:
          this.GetDouble(); return;
        case OpCode.Br_S: 
        case OpCode.Brfalse_S: 
        case OpCode.Brtrue_S: 
        case OpCode.Beq_S: 
        case OpCode.Bge_S: 
        case OpCode.Bgt_S: 
        case OpCode.Ble_S: 
        case OpCode.Blt_S: 
        case OpCode.Bne_Un_S: 
        case OpCode.Bge_Un_S: 
        case OpCode.Bgt_Un_S: 
        case OpCode.Ble_Un_S: 
        case OpCode.Blt_Un_S: 
        case OpCode.Leave_S:
          this.SkipBranch(true); return;
        case OpCode.Br: 
        case OpCode.Brfalse: 
        case OpCode.Brtrue: 
        case OpCode.Beq: 
        case OpCode.Bge: 
        case OpCode.Bgt: 
        case OpCode.Ble: 
        case OpCode.Blt: 
        case OpCode.Bne_Un: 
        case OpCode.Bge_Un: 
        case OpCode.Bgt_Un: 
        case OpCode.Ble_Un: 
        case OpCode.Blt_Un: 
        case OpCode.Leave:
          this.SkipBranch(false); return;
        case OpCode.Switch:
          this.SkipSwitch(); return;
        case OpCode.Ldftn:
        case OpCode.Ldvirtftn:
        case OpCode.Initobj:
        case OpCode.Constrained_:
        case OpCode.Sizeof:
          this.GetInt32(); return;
        case OpCode.Ldarg:
        case OpCode.Ldarga:
        case OpCode.Ldloc:
        case OpCode.Ldloca:
        case OpCode.Starg:
        case OpCode.Stloc:
          this.GetInt16(); return;
        case OpCode.Unaligned_:
          this.GetByte(); return;
        default:
          return;
      }
    }
    private void SkipBranch(bool shortOffset){
      int offset = shortOffset ? this.GetSByte() : this.GetInt32();
      Reader.GetOrCreateBlock(blockMap, this.counter + offset);
    }
    private void SkipSwitch(){
      int numCases = this.GetInt32();
      int offset = this.counter + numCases*4;
      for (int i = 0; i < numCases; i++){
        int targetAddress = this.GetInt32() + offset;
        Reader.GetOrCreateBlock(this.blockMap, targetAddress);
      }    
    }
    private Expression PopOperand()
    {
        return this.operandStack.Pop();
    }
#if FxCop || ILOFFSETS
    private OpCode opCode;
    private int ilOffset;
#endif
#if ILOFFSETS
    SourceContext lastSourceContext;
#endif
#if FxCop
    private SourceContext sourceContext;
    private Block currentBlock;
    private Dictionary<Block, List<TryNode>> tryMap;
    private Dictionary<int, Expression> handlerMap;
    internal StatementList/*!*/ ParseStatements() {
      this.tryMap = new Dictionary<Block, List<TryNode>>();
      this.handlerMap = new Dictionary<int, Expression>();
      this.ParseHeader();
      this.CreateBlocksForBranchTargets();
      currentBlock = null;
      this.sourceContext = new SourceContext();
      while (this.counter < size) {
        if (currentBlock == null) {
          currentBlock = Reader.GetOrCreateBlock(this.blockMap, this.counter);
        }
        bool endOfBasicBlock = this.ParseStatement(currentBlock);
        if (endOfBasicBlock) {
          currentBlock.SourceContext = currentBlock.Statements[0].SourceContext;
          currentBlock = null;
        }
      }
      Reader.GetOrCreateBlock(this.blockMap, this.counter);
      int counter = 0;
      Block block = new Block();
      block.Statements = new StatementList();
      ProcessBlock(block, ref counter, this.size, null);
      return block.Statements;
    }
    override protected void ParseExceptionHandlerEntry(bool smallSection) {
      int dataSize = this.reader.tables.GetByte();
      int n = (int)(ushort)this.reader.tables.GetInt16();
      if (smallSection)
        n = dataSize / 12;
      else
        n = (dataSize + (n << 8)) / 24;
      for (int i = 0; i < n; i++) {
        int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset;
        if (smallSection) {
          flags = this.reader.tables.GetInt16();
          tryOffset = this.reader.tables.GetUInt16();
          tryLength = this.reader.tables.GetByte();
          handlerOffset = this.reader.tables.GetUInt16();
          handlerLength = this.reader.tables.GetByte();
        }
        else {
          flags = this.reader.tables.GetInt32();
          tryOffset = this.reader.tables.GetInt32();
          tryLength = this.reader.tables.GetInt32();
          handlerOffset = this.reader.tables.GetInt32();
          handlerLength = this.reader.tables.GetInt32();
        }
        tokenOrOffset = this.reader.tables.GetInt32();
        Block tryStartBlock = Reader.GetOrCreateBlock(this.blockMap, tryOffset);
        Block blockAfterTryEnd = Reader.GetOrCreateBlock(this.blockMap, tryOffset + tryLength);
        Block handlerStartBlock = Reader.GetOrCreateBlock(this.blockMap, handlerOffset);
        Block blockAfterHandlerEnd = Reader.GetOrCreateBlock(this.blockMap, handlerOffset + handlerLength);
        List<TryNode> tryList = null;
        if (!this.tryMap.TryGetValue(tryStartBlock, out tryList)) {
          this.tryMap[tryStartBlock] = tryList = new List<TryNode>();
        }
        TryNode currentTry = null;
        int tryEnd = tryOffset + tryLength;
        foreach (TryNode t in tryList) {
          if (t.tryEnd == tryEnd) {
            currentTry = t;
            break;
          }
        }
        if (currentTry == null) {
          currentTry = new TryNode();
          currentTry.tryEnd = tryEnd;
          tryList.Add(currentTry);
        }
        int handlerEnd = handlerOffset + handlerLength;
        if (currentTry.handlersEnd < handlerEnd)
          currentTry.handlersEnd = handlerEnd;

        Debug.Assert((int)flags != 3);
        Debug.Assert((int)flags < 5);

        switch (flags) {
          case 0x00:
            // for a catch handler, tokenOrOffset represents
            // the metadata token of the handler type. handlerOffset
            // is the literal offset for the catch block
            int pos = this.reader.tables.GetCurrentPosition();
            TypeNode filterType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset);
            this.reader.tables.SetCurrentPosition(pos);
            string variableName = "$exception" + this.handlerMap.Count.ToString(CultureInfo.InvariantCulture);
            StackVariable exception = new StackVariable(filterType, variableName);
            CatchNode c = new CatchNode(handlerStartBlock, exception, filterType);
            c.handlerEnd = handlerEnd;
            currentTry.Catchers.Add(c);
            this.handlerMap[handlerOffset] = exception;
            break;
          case 0x01:
            // for a filter, tokenOrOffset represents the IL offset
            // of the filter block. handlerOffset represents
            // the IL offset of the associated catch handler
            Block filterExpression = Reader.GetOrCreateBlock(blockMap, tokenOrOffset);
            variableName = "$exception" + this.handlerMap.Count.ToString(CultureInfo.InvariantCulture);
            exception = new StackVariable(CoreSystemTypes.Object, variableName);
            Filter filter = new Filter(filterExpression, exception);
            filter.handlerEnd = handlerOffset;
            c = new CatchNode(handlerStartBlock, exception, null, filter);
            c.handlerEnd = handlerEnd;
            currentTry.Catchers.Add(c);
            // note that handlerOffset would not be correct here!
            this.handlerMap[tokenOrOffset] = exception;
            break;
          case 0x02:
            FinallyNode f = new FinallyNode(handlerStartBlock);
            f.handlerEnd = handlerEnd;
            currentTry.Finally = f;
            break;
          case 0x04:
            FaultHandler fh = new FaultHandler(handlerStartBlock);
            fh.handlerEnd = handlerEnd;
            currentTry.FaultHandler = fh;
            break;
        }
      }
    }
    private void ProcessBlock(Block currentBlock, ref int counter, int blockEnd, Node blockNode) {
      while (true) {
        int lastCounter = counter;
        Block block = GetNextBlock(ref counter);
        if (block == null || block.ILOffset >= blockEnd) {
          counter = lastCounter;
          if (blockNode != null)
            blockNode.SourceContext = currentBlock.Statements[0].SourceContext;
          return;
        }
        if (this.tryMap.ContainsKey(block)) {
          ProcessTryBlock(currentBlock, block, ref counter);
        }
        else {
          if (currentBlock.Statements.Count == 0)
            currentBlock.SourceContext = block.SourceContext;
          currentBlock.Statements.Add(block);
        }
      }
    }
    private void ProcessTryBlock(Block outerBlock, Block currentBlock, ref int counter) {
      List<TryNode> tryList = this.tryMap[currentBlock];
      TryNode outerTry = tryList[tryList.Count - 1];
      outerBlock.Statements.Add(outerTry);
      tryList.Remove(outerTry);
      if (tryList.Count > 0) {
        outerTry.Block = new Block();
        outerTry.Block.Statements = new StatementList();
        ProcessTryBlock(outerTry.Block, currentBlock, ref counter);
      }
      else {
        outerTry.Block = currentBlock;
      }
      this.tryMap.Remove(currentBlock);
      ProcessBlock(outerTry.Block, ref counter, outerTry.tryEnd, outerTry);
      while (true) {
        int lastCounter = counter;
        Block block = GetNextBlock(ref counter);
        if (counter >= outerTry.handlersEnd) {
          counter = lastCounter;
          return;
        }
        int handlerEnd;
        Node handlerNode;
        GetHandlerEnd(outerTry, block, out handlerEnd, out handlerNode);
        ProcessBlock(block, ref counter, handlerEnd, handlerNode);
      }
    }
    private Block GetNextBlock(ref int counter) {
      while (true) {
        Block result = this.blockMap[counter + 1] as Block;
        ++counter;
        if (result != null || counter >= this.size)
          return result;
      }
    }
    private void GetHandlerEnd(TryNode t, Block block, out int handlerEnd, out Node handlerNode) {
      handlerEnd = Int32.MaxValue;
      handlerNode = null;
      int startPos = block.ILOffset;
      if (t.Finally != null
        && t.Finally.handlerEnd > startPos
        && t.Finally.handlerEnd < handlerEnd) {
        handlerEnd = t.Finally.handlerEnd;
        handlerNode = t.Finally;
      }
      foreach (CatchNode c in t.Catchers) {
        if (c.handlerEnd > startPos && c.handlerEnd < handlerEnd) {
          handlerEnd = c.handlerEnd;
          handlerNode = c;
        }
        if (c.Filter != null && c.Filter.handlerEnd > startPos && c.Filter.handlerEnd < handlerEnd) {
          handlerEnd = c.Filter.handlerEnd;
          handlerNode = c.Filter;
        }
      }
      if (t.FaultHandler != null
        && t.FaultHandler.handlerEnd > startPos
        && t.FaultHandler.handlerEnd < handlerEnd) {
        handlerEnd = t.FaultHandler.handlerEnd;
        handlerNode = t.FaultHandler;
      }
    }
#endif
  }
  internal class InstructionParser : ILParser{
    private readonly TrivialHashtable/*!*/ ehMap;
    internal InstructionParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA)
      : base (reader, method, methodIndex, RVA){
      this.ehMap = new TrivialHashtable();
    }
    override protected void ParseExceptionHandlerEntry(bool smallSection){
      TrivialHashtable tryMap = new TrivialHashtable();
      int dataSize = this.reader.tables.GetByte();
      int n = (int)(ushort)this.reader.tables.GetInt16();
      if (smallSection)
        n = dataSize / 12;
      else
        n = (dataSize + (n << 8)) / 24;      
      for (int i = 0; i < n; i++){
        Instruction matchingInstruction;
        int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset;
        if (smallSection){
          flags = this.reader.tables.GetInt16();
          tryOffset = this.reader.tables.GetUInt16();
          tryLength = this.reader.tables.GetByte();
          handlerOffset = this.reader.tables.GetUInt16();
          handlerLength = this.reader.tables.GetByte();
        }else{
          flags = this.reader.tables.GetInt32();
          tryOffset = this.reader.tables.GetInt32();
          tryLength = this.reader.tables.GetInt32();
          handlerOffset = this.reader.tables.GetInt32();
          handlerLength = this.reader.tables.GetInt32();
        }
        tokenOrOffset = this.reader.tables.GetInt32();
        if (tryMap[tryOffset+tryLength] == null){
          matchingInstruction = this.AddInstruction(OpCode._Try, tryOffset);
          this.AddInstruction(OpCode._EndTry, tryOffset+tryLength, matchingInstruction);
          tryMap[tryOffset+tryLength] = String.Empty;
        }
        switch(flags){
          case 0x00: 
            int pos = this.reader.tables.GetCurrentPosition();
            TypeNode catchType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset);
            this.reader.tables.SetCurrentPosition(pos);
            matchingInstruction = this.AddInstruction(OpCode._Catch, handlerOffset, catchType);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          case 0x01:
            matchingInstruction = this.AddInstruction(OpCode._Filter, tokenOrOffset);
            this.AddInstruction(OpCode._EndFilter, handlerOffset, matchingInstruction);
            matchingInstruction = this.AddInstruction(OpCode._Catch, handlerOffset);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          case 0x02:
            matchingInstruction = this.AddInstruction(OpCode._Finally, handlerOffset);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          case 0x04:
            matchingInstruction = this.AddInstruction(OpCode._Fault, handlerOffset);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          default: throw new InvalidMetadataException(ExceptionStrings.BadExceptionHandlerType);
        }
      }
    }
    private Instruction AddInstruction(OpCode opCode, int offset){
      return this.AddInstruction(opCode, offset, null);
    }
    private Instruction AddInstruction(OpCode opCode, int offset, object value){
      Instruction instruction = new Instruction(opCode, offset, value);
      InstructionList instructions = (InstructionList)this.ehMap[offset+1];
      if (instructions == null) this.ehMap[offset+1] = instructions = new InstructionList(2);
      instructions.Add(instruction);
#if !ROTOR
      if (this.method.contextForOffset != null){
        object sctx = this.method.contextForOffset[offset + 1];
        if (sctx != null) instruction.SourceContext = (SourceContext)sctx;
      }
#endif
      return instruction;
    }
    private Int32List ParseSwitchInstruction(){
      int numTargets = this.GetInt32();
      Int32List result = new Int32List(numTargets);
      int offset = this.counter + numTargets*4;
      for (int i = 0; i < numTargets; i++){
        int targetAddress = this.GetInt32() + offset;
        result.Add(targetAddress);
      }
      return result;
    }
    internal InstructionList ParseInstructions(){
      this.ParseHeader();
      if (this.size == 0) return new InstructionList(0);
      InstructionList result = new InstructionList();
      result.Add(new Instruction(OpCode._Locals, 0, this.locals));
      while (this.counter <= size){
        InstructionList instructions = (InstructionList)this.ehMap[this.counter+1];
        if (instructions != null){
          for (int i = 0; i < instructions.Count; i++)
            result.Add(instructions[i]);
        }
        if (this.counter < size)
          result.Add(this.ParseInstruction());
        else 
          break;
      }
      return result;    
    }
    private SourceContext sourceContext = new SourceContext();
    internal Instruction ParseInstruction(){
      if (this.counter >= this.size) 
        return null;
      int offset = this.counter;
#if !ROTOR
      if (this.method.contextForOffset != null){
        object sctx = this.method.contextForOffset[offset+1];
        if (sctx != null) this.sourceContext = (SourceContext)sctx;
      }
#endif
      object value = null;
      OpCode opCode = this.GetOpCode();    
      switch(opCode){
        case OpCode.Nop:
        case OpCode.Break: 
          break;
        case OpCode.Ldarg_0: value = this.Parameters(0); break;
        case OpCode.Ldarg_1: value = this.Parameters(1); break;
        case OpCode.Ldarg_2: value = this.Parameters(2); break; 
        case OpCode.Ldarg_3: value = this.Parameters(3); break;
        case OpCode.Ldloc_0: value = this.locals[0]; break;
        case OpCode.Ldloc_1: value = this.locals[1]; break;
        case OpCode.Ldloc_2: value = this.locals[2]; break;
        case OpCode.Ldloc_3: value = this.locals[3]; break;
        case OpCode.Stloc_0: value = this.locals[0]; break;
        case OpCode.Stloc_1: value = this.locals[1]; break;
        case OpCode.Stloc_2: value = this.locals[2]; break;
        case OpCode.Stloc_3: value = this.locals[3]; break;
        case OpCode.Ldarg_S:  
        case OpCode.Ldarga_S:
        case OpCode.Starg_S:
          value = this.Parameters(this.GetByte()); break;
        case OpCode.Ldloc_S:
        case OpCode.Ldloca_S:
        case OpCode.Stloc_S:
          value = this.locals[this.GetByte()]; break;
        case OpCode.Ldnull: 
          break;
        case OpCode.Ldc_I4_M1: value = (Int32)(-1); break;
        case OpCode.Ldc_I4_0: value = (Int32)0; break;
        case OpCode.Ldc_I4_1: value = (Int32)1; break;
        case OpCode.Ldc_I4_2: value = (Int32)2; break;
        case OpCode.Ldc_I4_3: value = (Int32)3; break;
        case OpCode.Ldc_I4_4: value = (Int32)4; break;
        case OpCode.Ldc_I4_5: value = (Int32)5; break;
        case OpCode.Ldc_I4_6: value = (Int32)6; break;
        case OpCode.Ldc_I4_7: value = (Int32)7; break;
        case OpCode.Ldc_I4_8: value = (Int32)8; break;
        case OpCode.Ldc_I4_S: value = (Int32)this.GetSByte(); break;
        case OpCode.Ldc_I4: value = this.GetInt32(); break;
        case OpCode.Ldc_I8: value = this.GetInt64(); break;
        case OpCode.Ldc_R4: value = this.GetSingle(); break;
        case OpCode.Ldc_R8: value = this.GetDouble(); break;
        case OpCode.Dup:
        case OpCode.Pop: 
          break;
        case OpCode.Jmp: 
        case OpCode.Call:
          value = (Method)this.GetMemberFromToken(); break;
        case OpCode.Calli: 
          value = (FunctionPointer)this.reader.GetCalliSignature(this.GetInt32()); break;
        case OpCode.Ret: break;
        case OpCode.Br_S:
        case OpCode.Brfalse_S:
        case OpCode.Brtrue_S:
        case OpCode.Beq_S:
        case OpCode.Bge_S:
        case OpCode.Bgt_S:
        case OpCode.Ble_S:
        case OpCode.Blt_S:
        case OpCode.Bne_Un_S:
        case OpCode.Bge_Un_S:
        case OpCode.Bgt_Un_S:
        case OpCode.Ble_Un_S:
        case OpCode.Blt_Un_S:
          value = this.counter + 1 + this.GetSByte(); break;
        case OpCode.Br:
        case OpCode.Brfalse:
        case OpCode.Brtrue:
        case OpCode.Beq:
        case OpCode.Bge:
        case OpCode.Bgt:
        case OpCode.Ble:
        case OpCode.Blt:
        case OpCode.Bne_Un:
        case OpCode.Bge_Un:
        case OpCode.Bgt_Un:
        case OpCode.Ble_Un:
        case OpCode.Blt_Un:
          value = this.counter + 4 + this.GetInt32(); break;
        case OpCode.Switch: value = this.ParseSwitchInstruction(); break;        
        case OpCode.Ldind_I1: 
        case OpCode.Ldind_U1:
        case OpCode.Ldind_I2:
        case OpCode.Ldind_U2:
        case OpCode.Ldind_I4:
        case OpCode.Ldind_U4:
        case OpCode.Ldind_I8:
        case OpCode.Ldind_I:
        case OpCode.Ldind_R4:
        case OpCode.Ldind_R8:
        case OpCode.Ldind_Ref:
        case OpCode.Stind_Ref:
        case OpCode.Stind_I1:
        case OpCode.Stind_I2:
        case OpCode.Stind_I4:
        case OpCode.Stind_I8:
        case OpCode.Stind_R4:
        case OpCode.Stind_R8:
        case OpCode.Add:
        case OpCode.Sub:
        case OpCode.Mul:
        case OpCode.Div:
        case OpCode.Div_Un:
        case OpCode.Rem:
        case OpCode.Rem_Un:
        case OpCode.And:
        case OpCode.Or:
        case OpCode.Xor:
        case OpCode.Shl:
        case OpCode.Shr:
        case OpCode.Shr_Un:
        case OpCode.Neg:
        case OpCode.Not:
        case OpCode.Conv_I1:
        case OpCode.Conv_I2:
        case OpCode.Conv_I4:
        case OpCode.Conv_I8:
        case OpCode.Conv_R4:
        case OpCode.Conv_R8:
        case OpCode.Conv_U4:
        case OpCode.Conv_U8:
          break;
        case OpCode.Callvirt: value = (Method)this.GetMemberFromToken(); break;
        case OpCode.Cpobj:
        case OpCode.Ldobj: 
          value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Ldstr: value = this.GetStringFromToken(); break;          
        case OpCode.Newobj: value = (Method)this.GetMemberFromToken();break;
        case OpCode.Castclass:
        case OpCode.Isinst: 
          value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Conv_R_Un: break;       
        case OpCode.Unbox: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Throw: break;
        case OpCode.Ldfld: 
        case OpCode.Ldflda:
        case OpCode.Stfld:
        case OpCode.Ldsfld:
        case OpCode.Ldsflda:
        case OpCode.Stsfld:
        case OpCode.Stobj:
          value = this.GetMemberFromToken(); break;
        case OpCode.Conv_Ovf_I1_Un:
        case OpCode.Conv_Ovf_I2_Un:
        case OpCode.Conv_Ovf_I4_Un:
        case OpCode.Conv_Ovf_I8_Un:
        case OpCode.Conv_Ovf_U1_Un:
        case OpCode.Conv_Ovf_U2_Un:
        case OpCode.Conv_Ovf_U4_Un:
        case OpCode.Conv_Ovf_U8_Un:
        case OpCode.Conv_Ovf_I_Un:
        case OpCode.Conv_Ovf_U_Un:
          break;
        case OpCode.Box:
        case OpCode.Newarr: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Ldlen: break;
        case OpCode.Ldelema: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Ldelem_I1:
        case OpCode.Ldelem_U1:
        case OpCode.Ldelem_I2:
        case OpCode.Ldelem_U2:
        case OpCode.Ldelem_I4:
        case OpCode.Ldelem_U4:
        case OpCode.Ldelem_I8:
        case OpCode.Ldelem_I:
        case OpCode.Ldelem_R4:
        case OpCode.Ldelem_R8:
        case OpCode.Ldelem_Ref: 
        case OpCode.Stelem_I:
        case OpCode.Stelem_I1:
        case OpCode.Stelem_I2:
        case OpCode.Stelem_I4:
        case OpCode.Stelem_I8:
        case OpCode.Stelem_R4:
        case OpCode.Stelem_R8:
        case OpCode.Stelem_Ref:
          break;
        case OpCode.Ldelem: 
          value = (TypeNode)this.GetMemberFromToken();
          break;
        case OpCode.Stelem: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Unbox_Any: value = this.GetMemberFromToken(); break;
        case OpCode.Conv_Ovf_I1:
        case OpCode.Conv_Ovf_U1:
        case OpCode.Conv_Ovf_I2:
        case OpCode.Conv_Ovf_U2:
        case OpCode.Conv_Ovf_I4:
        case OpCode.Conv_Ovf_U4:
        case OpCode.Conv_Ovf_I8:
        case OpCode.Conv_Ovf_U8:
          break;
        case OpCode.Refanyval: value = this.GetMemberFromToken(); break;
        case OpCode.Ckfinite: break;
        case OpCode.Mkrefany: value = this.GetMemberFromToken(); break;
        case OpCode.Ldtoken: value = this.GetMemberFromToken(); break;
        case OpCode.Conv_U2:
        case OpCode.Conv_U1:
        case OpCode.Conv_I:
        case OpCode.Conv_Ovf_I:
        case OpCode.Conv_Ovf_U:
        case OpCode.Add_Ovf:
        case OpCode.Add_Ovf_Un:
        case OpCode.Mul_Ovf:
        case OpCode.Mul_Ovf_Un:
        case OpCode.Sub_Ovf:
        case OpCode.Sub_Ovf_Un:
        case OpCode.Endfinally: 
          break;
        case OpCode.Leave:   value = this.counter + 4 + this.GetInt32(); break; 
        case OpCode.Leave_S: value = this.counter + 1 + this.GetSByte(); break;
        case OpCode.Stind_I:
        case OpCode.Conv_U:
        case OpCode.Prefix7:
        case OpCode.Prefix6:
        case OpCode.Prefix5:
        case OpCode.Prefix4:
        case OpCode.Prefix3:
        case OpCode.Prefix2:
        case OpCode.Prefix1:
        case OpCode.Arglist:
        case OpCode.Ceq:
        case OpCode.Cgt:
        case OpCode.Cgt_Un:
        case OpCode.Clt:
        case OpCode.Clt_Un:
          break;
        case OpCode.Ldftn:
        case OpCode.Ldvirtftn:
          value = this.GetMemberFromToken(); break;
        case OpCode.Ldarg:
        case OpCode.Ldarga:
        case OpCode.Starg:
          value = this.Parameters(this.GetInt16()); break;
        case OpCode.Ldloc:
        case OpCode.Ldloca:
        case OpCode.Stloc:
          value = this.locals[this.GetInt16()]; break;
        case OpCode.Localloc:
        case OpCode.Endfilter:
          break;
        case OpCode.Unaligned_: value = this.GetByte(); break;
        case OpCode.Volatile_:
        case OpCode.Tail_:
          break;
        case OpCode.Initobj: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Constrained_: value = this.GetMemberFromToken() as TypeNode; break;
        case OpCode.Cpblk: 
        case OpCode.Initblk:
          break;
        case OpCode.Rethrow:
          break;
        case OpCode.Sizeof: value = this.GetMemberFromToken(); break;
        case OpCode.Refanytype:
        case OpCode.Readonly_:
          break;
        default: throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, 
          ExceptionStrings.UnknownOpCodeEncountered, opCode.ToString("x")));
      }
      Instruction instruction = new Instruction(opCode, offset, value);
      instruction.SourceContext = this.sourceContext;
      return instruction;
    }
  }
  internal class ExpressionStack{
    internal Expression[]/*!*/ elements = new Expression[16];
    internal int top = -1;

    internal ExpressionStack() {
      //^ base();
    }

    private void Grow(){
      int n = this.elements.Length;
      Expression[] newElements = new Expression[n+64];
      for (int i = 0; i < n; i++) newElements[i] = this.elements[i];
      this.elements = newElements;
    }
    internal Expression/*!*/ Pop() {
      if (this.top < 0) return new Expression(NodeType.Pop);
      Expression e = this.elements[this.top--];
      //^ assume e != null;
      return e;
    }
    internal void Push(Expression/*!*/ e) {
      if (++this.top >= this.elements.Length) this.Grow();
      this.elements[this.top] = e;
    }
  }
  /// <summary>
  /// A thin wrapper for a synchronized System.Collections.Hashtable that inserts and strips WeakReference wrappers for the values stored in the table.
  /// </summary>
  internal class SynchronizedWeakDictionary : IDictionary{
    readonly private Hashtable/*!*/ Hashtable = System.Collections.Hashtable.Synchronized(new Hashtable());

    internal SynchronizedWeakDictionary() {
      //^ base();
    }

    public void Add(object/*!*/ key, object value){
      this.Hashtable.Add(key, new WeakReference(value));
    }
    public void Clear(){
      this.Hashtable.Clear();
    }
    public bool Contains(object/*!*/ key) {
      return this.Hashtable.Contains(key);
    }
    public IDictionaryEnumerator/*!*/ GetEnumerator() {
      return this.Hashtable.GetEnumerator();
    }
    public bool IsFixedSize{
      get{return false;}
    }
    public bool IsReadOnly{
      get{return false;}
    }
    public ICollection/*!*/ Keys {
      get{return this.Hashtable.Keys;}
    }
    public void Remove(object/*!*/ key) {
      this.Hashtable.Remove(key);
    }
    public ICollection/*!*/ Values {
      get{return new WeakValuesCollection(this.Hashtable.Values);}
    }
    public object this[object/*!*/ key] {
      get{
        WeakReference wref = (WeakReference)this.Hashtable[key];
        if (wref == null) return null;
        return wref.Target;
      }
      set{
        this.Hashtable[key] = new WeakReference(value);
      }
    }
    public void CopyTo(Array/*!*/ array, int index){
      IEnumerator enumerator = this.GetEnumerator();
      for (int i = 0; enumerator.MoveNext(); i++)
        array.SetValue(enumerator.Current, index+i);
    }
    public int Count{
      get{return this.Hashtable.Count;}
    }
    public bool IsSynchronized{
      get{return false;}
    }
    public object/*!*/ SyncRoot {
      get{return this.Hashtable.SyncRoot;}
    }
    IEnumerator/*!*/ IEnumerable.GetEnumerator(){
      return new WeakValuesEnumerator(this.Hashtable.GetEnumerator());
    }
  }
  internal class WeakValuesCollection : ICollection{
    readonly private ICollection/*!*/ collection;

    internal WeakValuesCollection(ICollection/*!*/ collection){
      this.collection = collection;
      //^ base();
    }

    public void CopyTo(Array/*!*/ array, int index){
      IEnumerator enumerator = this.GetEnumerator();
      for (int i = 0; enumerator.MoveNext(); i++)
        array.SetValue(enumerator.Current, index+i);
    }
    public int Count{
      get {return this.collection.Count;}
    }
    public bool IsSynchronized{
      get {return this.collection.IsSynchronized;}
    }
    public object/*!*/ SyncRoot {
      get {return this.collection.SyncRoot;}
    }
    public IEnumerator/*!*/ GetEnumerator(){
      return new WeakValuesEnumerator(this.collection.GetEnumerator());
    }
  }
  internal class WeakValuesEnumerator : IEnumerator{
    readonly private IEnumerator/*!*/ enumerator;

    internal WeakValuesEnumerator(IEnumerator/*!*/ enumerator){
      this.enumerator = enumerator;
      //^ base();
    }

    public object Current{
      get{
        object curr = this.enumerator.Current;
        if (curr is DictionaryEntry){
          DictionaryEntry dicEntry = (DictionaryEntry)curr;
          curr = dicEntry.Value;
        }
        WeakReference wref = curr as WeakReference;
        if (wref != null) return wref.Target;
        return null;
      }
    }
    public bool MoveNext(){
      return this.enumerator.MoveNext();
    }
    public void Reset(){
      this.enumerator.Reset();
    }
  }
#if !ROTOR && NoWriter
  [ComVisible(true), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")]
  internal interface IMetaDataImport{}
  internal class EmptyImporter : IMetaDataImport{}
#endif
#if FxCop
  class StackVariable : Local {
    internal StackVariable(TypeNode type, string name)
      : base(type) {
      this.NodeType = NodeType.StackVariable;
      this.Name = Identifier.For(name);
    }
    internal StackVariable(TypeNode type, int index)
      : base(type) {
      this.NodeType = NodeType.StackVariable;
      this.Name = Identifier.For("stack$" + index.ToString(CultureInfo.InvariantCulture));
    }
  }
#endif
}
